From 28514476ef8c824c3d189d98f23d0f8d23e496ea Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 31 Oct 2022 20:29:55 -0700 Subject: [PATCH 01/68] remove `-fstage1` option After this commit, the self-hosted compiler does not offer the option to use stage1 as a backend anymore. --- CMakeLists.txt | 1 - build.zig | 123 +----------------------- lib/build_runner.zig | 6 -- lib/std/build.zig | 16 ---- lib/std/build/TranslateCStep.zig | 14 --- src/Compilation.zig | 127 +++++++++---------------- src/Sema.zig | 2 - src/link.zig | 23 +---- src/link/Coff.zig | 3 +- src/link/Coff/lld.zig | 20 +--- src/link/Elf.zig | 23 +---- src/link/MachO.zig | 8 +- src/link/MachO/zld.zig | 19 +--- src/link/Wasm.zig | 54 +++-------- src/main.zig | 25 +---- src/test.zig | 1 - src/translate_c.zig | 27 +----- src/translate_c/ast.zig | 48 ++++------ test/link/wasm/archive/build.zig | 1 - test/link/wasm/bss/build.zig | 1 - test/link/wasm/producers/build.zig | 1 - test/link/wasm/segments/build.zig | 1 - test/link/wasm/stack_pointer/build.zig | 1 - test/link/wasm/type/build.zig | 1 - test/tests.zig | 10 +- 25 files changed, 95 insertions(+), 461 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 015832913fd1..e289a79348c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1084,7 +1084,6 @@ set(ZIG_BUILD_ARGS --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" "-Dconfig_h=${ZIG_CONFIG_H_OUT}" "-Denable-llvm" - "-Denable-stage1" ${ZIG_RELEASE_ARG} ${ZIG_STATIC_ARG} ${ZIG_NO_LIB_ARG} diff --git a/build.zig b/build.zig index 69f65d2a5939..adab2b241177 100644 --- a/build.zig +++ b/build.zig @@ -69,9 +69,8 @@ pub fn build(b: *Builder) !void { const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; - const have_stage1 = b.option(bool, "enable-stage1", "Include the stage1 compiler behind a feature flag") orelse false; const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false; - const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (have_stage1 or static_llvm); + const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse static_llvm; const llvm_has_m68k = b.option( bool, "llvm-has-m68k", @@ -133,7 +132,6 @@ pub fn build(b: *Builder) !void { const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; const strip = b.option(bool, "strip", "Omit debug information") orelse false; - const use_zig0 = b.option(bool, "zig0", "Bootstrap using zig0") orelse false; const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { @@ -146,11 +144,7 @@ pub fn build(b: *Builder) !void { target.ofmt = .c; } - const main_file: ?[]const u8 = mf: { - if (!have_stage1) break :mf "src/main.zig"; - if (use_zig0) break :mf null; - break :mf "src/stage1.zig"; - }; + const main_file: ?[]const u8 = "src/main.zig"; const exe = b.addExecutable("zig", main_file); @@ -264,92 +258,6 @@ pub fn build(b: *Builder) !void { } }; - if (have_stage1) { - const softfloat = b.addStaticLibrary("softfloat", null); - softfloat.setBuildMode(.ReleaseFast); - softfloat.setTarget(target); - softfloat.addIncludePath("deps/SoftFloat-3e-prebuilt"); - softfloat.addIncludePath("deps/SoftFloat-3e/source/8086"); - softfloat.addIncludePath("deps/SoftFloat-3e/source/include"); - softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" }); - softfloat.single_threaded = single_threaded; - - const zig0 = b.addExecutable("zig0", null); - zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags); - zig0.addIncludePath("zig-cache/tmp"); // for config.h - zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major})); - zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor})); - zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch})); - zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version})); - - for ([_]*std.build.LibExeObjStep{ zig0, exe, test_cases }) |artifact| { - artifact.addIncludePath("src"); - artifact.addIncludePath("deps/SoftFloat-3e/source/include"); - artifact.addIncludePath("deps/SoftFloat-3e-prebuilt"); - - artifact.defineCMacro("ZIG_LINK_MODE", "Static"); - - artifact.addCSourceFiles(&stage1_sources, &exe_cflags); - artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" }); - - artifact.linkLibrary(softfloat); - artifact.linkLibCpp(); - } - - try addStaticLlvmOptionsToExe(zig0); - - const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch()); - const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) }); - const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" }); - - const zig1_obj = zig0.run(); - zig1_obj.addArgs(&.{ - "src/stage1.zig", - "-target", - try target.zigTriple(b.allocator), - "-mcpu=baseline", - "--name", - "zig1", - "--zig-lib-dir", - b.pathFromRoot("lib"), - b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}), - "-fcompiler-rt", - "-lc", - }); - { - zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" }); - zig1_obj.addFileSourceArg(exe_options.getSource()); - zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" }); - } - switch (mode) { - .Debug => {}, - .ReleaseFast => { - zig1_obj.addArg("-OReleaseFast"); - zig1_obj.addArg("-fstrip"); - }, - .ReleaseSafe => { - zig1_obj.addArg("-OReleaseSafe"); - zig1_obj.addArg("-fstrip"); - }, - .ReleaseSmall => { - zig1_obj.addArg("-OReleaseSmall"); - zig1_obj.addArg("-fstrip"); - }, - } - if (single_threaded orelse false) { - zig1_obj.addArg("-fsingle-threaded"); - } - - if (use_zig0) { - exe.step.dependOn(&zig1_obj.step); - exe.addObjectFile(zig1_obj_path); - } - - // This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case - // of being built by cmake. But when built by zig it's gonna get a compiler_rt so that - // is pointless. - exe.addPackagePath("compiler_rt", "src/empty.zig"); - } if (cmake_cfg) |cfg| { // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD. // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find @@ -379,7 +287,6 @@ pub fn build(b: *Builder) !void { exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); exe_options.addOption(bool, "value_tracing", value_tracing); - exe_options.addOption(bool, "have_stage1", have_stage1); if (tracy) |tracy_path| { const client_cpp = fs.path.join( b.allocator, @@ -414,7 +321,6 @@ pub fn build(b: *Builder) !void { test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); test_cases_options.addOption(bool, "skip_non_native", skip_non_native); test_cases_options.addOption(bool, "skip_stage1", skip_stage1); - test_cases_options.addOption(bool, "have_stage1", have_stage1); test_cases_options.addOption(bool, "have_llvm", enable_llvm); test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k); test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky); @@ -1010,31 +916,6 @@ const softfloat_sources = [_][]const u8{ "deps/SoftFloat-3e/source/ui64_to_extF80M.c", }; -const stage1_sources = [_][]const u8{ - "src/stage1/analyze.cpp", - "src/stage1/astgen.cpp", - "src/stage1/bigfloat.cpp", - "src/stage1/bigint.cpp", - "src/stage1/buffer.cpp", - "src/stage1/codegen.cpp", - "src/stage1/errmsg.cpp", - "src/stage1/error.cpp", - "src/stage1/heap.cpp", - "src/stage1/ir.cpp", - "src/stage1/ir_print.cpp", - "src/stage1/mem.cpp", - "src/stage1/os.cpp", - "src/stage1/parser.cpp", - "src/stage1/range_set.cpp", - "src/stage1/stage1.cpp", - "src/stage1/target.cpp", - "src/stage1/tokenizer.cpp", - "src/stage1/util.cpp", - "src/stage1/softfloat_ext.cpp", -}; -const optimized_c_sources = [_][]const u8{ - "src/stage1/parse_f128.c", -}; const zig_cpp_sources = [_][]const u8{ // These are planned to stay even when we are self-hosted. "src/zig_llvm.cpp", diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 510bae4a521e..735ddb9de185 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -183,10 +183,6 @@ pub fn main() !void { builder.enable_darling = true; } else if (mem.eql(u8, arg, "-fno-darling")) { builder.enable_darling = false; - } else if (mem.eql(u8, arg, "-fstage1")) { - builder.use_stage1 = true; - } else if (mem.eql(u8, arg, "-fno-stage1")) { - builder.use_stage1 = false; } else if (mem.eql(u8, arg, "-freference-trace")) { builder.reference_trace = 256; } else if (mem.startsWith(u8, arg, "-freference-trace=")) { @@ -318,8 +314,6 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void try out_stream.writeAll( \\ \\Advanced Options: - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ --build-file [file] Override path to build.zig diff --git a/lib/std/build.zig b/lib/std/build.zig index 77f0779c603e..73487d8ea9ab 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -46,7 +46,6 @@ pub const Builder = struct { prominent_compile_errors: bool, color: enum { auto, on, off } = .auto, reference_trace: ?u32 = null, - use_stage1: ?bool = null, invalid_user_input: bool, zig_exe: []const u8, default_step: *Step, @@ -1621,7 +1620,6 @@ pub const LibExeObjStep = struct { stack_size: ?u64 = null, want_lto: ?bool = null, - use_stage1: ?bool = null, use_llvm: ?bool = null, use_lld: ?bool = null, @@ -2467,20 +2465,6 @@ pub const LibExeObjStep = struct { try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some})); } - if (self.use_stage1) |stage1| { - if (stage1) { - try zig_args.append("-fstage1"); - } else { - try zig_args.append("-fno-stage1"); - } - } else if (builder.use_stage1) |stage1| { - if (stage1) { - try zig_args.append("-fstage1"); - } else { - try zig_args.append("-fno-stage1"); - } - } - if (self.use_llvm) |use_llvm| { if (use_llvm) { try zig_args.append("-fLLVM"); diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 7d7f2a62a46b..1f9bee463c74 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -21,7 +21,6 @@ output_dir: ?[]const u8, out_basename: []const u8, target: CrossTarget = CrossTarget{}, output_file: build.GeneratedFile, -use_stage1: ?bool = null, pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; @@ -92,19 +91,6 @@ fn make(step: *Step) !void { try argv_list.append("-D"); try argv_list.append(c_macro); } - if (self.use_stage1) |stage1| { - if (stage1) { - try argv_list.append("-fstage1"); - } else { - try argv_list.append("-fno-stage1"); - } - } else if (self.builder.use_stage1) |stage1| { - if (stage1) { - try argv_list.append("-fstage1"); - } else { - try argv_list.append("-fno-stage1"); - } - } try argv_list.append(self.source.getPath(self.builder)); diff --git a/src/Compilation.zig b/src/Compilation.zig index 48cf246287cb..a0b78394e711 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -935,7 +935,6 @@ pub const InitOptions = struct { use_llvm: ?bool = null, use_lld: ?bool = null, use_clang: ?bool = null, - use_stage1: ?bool = null, single_threaded: ?bool = null, strip: ?bool = null, formatted_panics: ?bool = null, @@ -1133,9 +1132,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const comp = try arena.create(Compilation); const root_name = try arena.dupeZ(u8, options.root_name); - const use_stage1 = options.use_stage1 orelse false; - if (use_stage1 and !build_options.have_stage1) return error.ZigCompilerBuiltWithoutStage1; - // Make a decision on whether to use LLVM or our own backend. const use_llvm = build_options.have_llvm and blk: { if (options.use_llvm) |explicit| @@ -1149,11 +1145,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (options.main_pkg == null) break :blk false; - // The stage1 compiler depends on the stage1 C++ LLVM backend - // to compile zig code. - if (use_stage1) - break :blk true; - // If LLVM does not support the target, then we can't use it. if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) break :blk false; @@ -1181,8 +1172,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // compiler state, the second clause here can be removed so that incremental // cache mode is used for LLVM backend too. We need some fuzz testing before // that can be enabled. - const cache_mode = if ((use_stage1 and !options.disable_lld_caching) or - (use_llvm and !options.disable_lld_caching)) CacheMode.whole else options.cache_mode; + const cache_mode = if (use_llvm and !options.disable_lld_caching) + CacheMode.whole + else + options.cache_mode; const tsan = options.want_tsan orelse false; // TSAN is implemented in C++ so it requires linking libc++. @@ -1545,7 +1538,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // Synchronize with other matching comments: ZigOnlyHashStuff hash.add(valgrind); hash.add(single_threaded); - hash.add(use_stage1); hash.add(use_llvm); hash.add(dll_export_fns); hash.add(options.is_test); @@ -1587,9 +1579,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .handle = artifact_dir, .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}), }; - log.debug("zig_cache_artifact_directory='{?s}' use_stage1={}", .{ - zig_cache_artifact_directory.path, use_stage1, - }); const builtin_pkg = try Package.createWithDir( gpa, @@ -1907,7 +1896,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .subsystem = options.subsystem, .is_test = options.is_test, .wasi_exec_model = wasi_exec_model, - .use_stage1 = use_stage1, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .native_darwin_sdk = options.native_darwin_sdk, @@ -2344,7 +2332,6 @@ pub fn update(comp: *Compilation) !void { comp.c_object_work_queue.writeItemAssumeCapacity(key); } - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; if (comp.bin_file.options.module) |module| { module.compile_log_text.shrinkAndFree(module.gpa, 0); module.generation += 1; @@ -2360,7 +2347,7 @@ pub fn update(comp: *Compilation) !void { // import_table here. // Likewise, in the case of `zig test`, the test runner is the root source file, // and so there is nothing to import the main file. - if (use_stage1 or comp.bin_file.options.is_test) { + if (comp.bin_file.options.is_test) { _ = try module.importPkg(module.main_pkg); } @@ -2374,21 +2361,19 @@ pub fn update(comp: *Compilation) !void { comp.astgen_work_queue.writeItemAssumeCapacity(value); } - if (!use_stage1) { - // Put a work item in for checking if any files used with `@embedFile` changed. - { - try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); - var it = module.embed_table.iterator(); - while (it.next()) |entry| { - const embed_file = entry.value_ptr.*; - comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file); - } + // Put a work item in for checking if any files used with `@embedFile` changed. + { + try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); + var it = module.embed_table.iterator(); + while (it.next()) |entry| { + const embed_file = entry.value_ptr.*; + comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file); } + } - try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); - if (comp.bin_file.options.is_test) { - try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); - } + try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); + if (comp.bin_file.options.is_test) { + try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); } } @@ -2400,36 +2385,34 @@ pub fn update(comp: *Compilation) !void { try comp.performAllTheWork(main_progress_node); - if (!use_stage1) { - if (comp.bin_file.options.module) |module| { - if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { - // The `test_functions` decl has been intentionally postponed until now, - // at which point we must populate it with the list of test functions that - // have been discovered and not filtered out. - try module.populateTestFunctions(main_progress_node); - } + if (comp.bin_file.options.module) |module| { + if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { + // The `test_functions` decl has been intentionally postponed until now, + // at which point we must populate it with the list of test functions that + // have been discovered and not filtered out. + try module.populateTestFunctions(main_progress_node); + } - // Process the deletion set. We use a while loop here because the - // deletion set may grow as we call `clearDecl` within this loop, - // and more unreferenced Decls are revealed. - while (module.deletion_set.count() != 0) { - const decl_index = module.deletion_set.keys()[0]; - const decl = module.declPtr(decl_index); - assert(decl.deletion_flag); - assert(decl.dependants.count() == 0); - const is_anon = if (decl.zir_decl_index == 0) blk: { - break :blk decl.src_namespace.anon_decls.swapRemove(decl_index); - } else false; - - try module.clearDecl(decl_index, null); - - if (is_anon) { - module.destroyDecl(decl_index); - } - } + // Process the deletion set. We use a while loop here because the + // deletion set may grow as we call `clearDecl` within this loop, + // and more unreferenced Decls are revealed. + while (module.deletion_set.count() != 0) { + const decl_index = module.deletion_set.keys()[0]; + const decl = module.declPtr(decl_index); + assert(decl.deletion_flag); + assert(decl.dependants.count() == 0); + const is_anon = if (decl.zir_decl_index == 0) blk: { + break :blk decl.src_namespace.anon_decls.swapRemove(decl_index); + } else false; + + try module.clearDecl(decl_index, null); - try module.processExports(); + if (is_anon) { + module.destroyDecl(decl_index); + } } + + try module.processExports(); } if (comp.totalErrorCount() != 0) { @@ -2536,11 +2519,8 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { }; comp.link_error_flags = comp.bin_file.errorFlags(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - if (!use_stage1) { - if (comp.bin_file.options.module) |module| { - try link.File.C.flushEmitH(module); - } + if (comp.bin_file.options.module) |module| { + try link.File.C.flushEmitH(module); } } @@ -2610,7 +2590,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes // Synchronize with other matching comments: ZigOnlyHashStuff man.hash.add(comp.bin_file.options.valgrind); man.hash.add(comp.bin_file.options.single_threaded); - man.hash.add(comp.bin_file.options.use_stage1); man.hash.add(comp.bin_file.options.use_llvm); man.hash.add(comp.bin_file.options.dll_export_fns); man.hash.add(comp.bin_file.options.is_test); @@ -3010,8 +2989,6 @@ pub fn performAllTheWork( comp.work_queue_wait_group.reset(); defer comp.work_queue_wait_group.wait(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - { const astgen_frame = tracy.namedFrame("astgen"); defer astgen_frame.end(); @@ -3056,7 +3033,7 @@ pub fn performAllTheWork( } } - if (!use_stage1) { + { const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls"); defer outdated_and_deleted_decls_frame.end(); @@ -3064,15 +3041,6 @@ pub fn performAllTheWork( if (comp.bin_file.options.module) |mod| { try mod.processOutdatedAndDeletedDecls(); } - } else if (comp.bin_file.options.module) |mod| { - // If there are any AstGen compile errors, report them now to avoid - // hitting stage1 bugs. - if (mod.failed_files.count() != 0) { - return; - } - comp.updateStage1Module(main_progress_node) catch |err| { - fatal("unable to build stage1 zig object: {s}", .{@errorName(err)}); - }; } if (comp.bin_file.options.module) |mod| { @@ -3598,10 +3566,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { var man = comp.obtainCObjectCacheManifest(); defer man.deinit(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(use_stage1); man.hash.addBytes(c_src); // If the previous invocation resulted in clang errors, we will see a hit @@ -3665,7 +3630,6 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { new_argv.ptr + new_argv.len, &clang_errors, c_headers_dir_path_z, - use_stage1, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ASTUnitFailure => { @@ -5097,8 +5061,6 @@ pub fn dump_argv(argv: []const []const u8) void { } pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - if (use_stage1) return .stage1; if (build_options.have_llvm and comp.bin_file.options.use_llvm) return .stage2_llvm; const target = comp.bin_file.options.target; if (target.ofmt == .c) return .stage2_c; @@ -5394,7 +5356,6 @@ fn buildOutputFromZig( .link_mode = .Static, .function_sections = true, .no_builtin = true, - .use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1, .want_sanitize_c = false, .want_stack_check = false, .want_stack_protector = 0, diff --git a/src/Sema.zig b/src/Sema.zig index debd18005abb..a85c80826edc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2121,8 +2121,6 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError const msg = msg: { const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{}); errdefer msg.destroy(sema.gpa); - - try sema.errNote(block, src, msg, "to use async enable the stage1 compiler with either '-fstage1' or by setting '.use_stage1 = true` in your 'build.zig' script", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); diff --git a/src/link.zig b/src/link.zig index 4dfcf171af15..e57ffd425662 100644 --- a/src/link.zig +++ b/src/link.zig @@ -155,7 +155,6 @@ pub const Options = struct { build_id: bool, disable_lld_caching: bool, is_test: bool, - use_stage1: bool, hash_style: HashStyle, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, @@ -293,8 +292,7 @@ pub const File = struct { return &(try MachO.openPath(allocator, options)).base; } - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_stage1 or options.emit == null) { + if (options.emit == null) { return switch (options.target.ofmt) { .coff => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, @@ -983,24 +981,7 @@ pub const File = struct { // 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 (base.options.module) |module| blk: { - const use_stage1 = build_options.have_stage1 and base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = base.options.root_name, - .target = base.options.target, - .output_mode = .Obj, - }); - switch (base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path_z).?, obj_basename, - }), - } - } + const module_obj_path: ?[]const u8 = if (base.options.module != null) blk: { try base.flushModule(comp, prog_node); const dirname = fs.path.dirname(full_out_path_z) orelse "."; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 3f89de960881..aa94704c5451 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -248,8 +248,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } return self; diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 7c53ef30bdb4..c1edb55b8092 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -30,25 +30,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // 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: { - const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = self.base.options.root_name, - .target = self.base.options.target, - .output_mode = .Obj, - }); - switch (self.base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (self.base.options.module != null) blk: { try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f98e33e58b2a..b7968b3f1c10 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -328,8 +328,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { .page_size = page_size, }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } return self; @@ -1228,25 +1227,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // 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: { - // stage1 puts the object file in the cache directory. - if (self.base.options.use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = self.base.options.root_name, - .target = self.base.options.target, - .output_mode = .Obj, - }); - switch (self.base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (self.base.options.module != null) blk: { try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index fb651edbe38e..8c9e5329f2ec 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -290,8 +290,7 @@ pub const Export = struct { pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { assert(options.target.ofmt == .macho); - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_stage1 or options.emit == null or options.module == null) { + if (options.emit == null or options.module == null) { return createEmpty(allocator, options); } @@ -377,7 +376,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { const cpu_arch = options.target.cpu.arch; const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; const self = try gpa.create(MachO); errdefer gpa.destroy(self); @@ -390,13 +388,13 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { .file = null, }, .page_size = page_size, - .mode = if (use_stage1 or use_llvm or options.module == null or options.cache_mode == .whole) + .mode = if (use_llvm or options.module == null or options.cache_mode == .whole) .one_shot else .incremental, }; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 5baaf71f18b0..9baecd326a3c 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -3746,24 +3746,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr // 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 (options.module) |module| blk: { - if (options.use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = options.root_name, - .target = target, - .output_mode = .Obj, - }); - switch (options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (options.module != null) blk: { try macho_file.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index adcb539bd65a..4a9db75c9806 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -382,8 +382,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { wasm.llvm_object = try LlvmObject.create(gpa, options); } return wasm; @@ -2986,25 +2985,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // 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 (wasm.base.options.module) |mod| blk: { - const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = wasm.base.options.root_name, - .target = wasm.base.options.target, - .output_mode = .Obj, - }); - switch (wasm.base.options.cache_mode) { - .incremental => break :blk try mod.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (wasm.base.options.module != null) blk: { try wasm.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { @@ -3198,26 +3179,19 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! if (wasm.base.options.module) |mod| { // when we use stage1, we use the exports that stage1 provided us. // For stage2, we can directly retrieve them from the module. - const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1; - if (use_stage1) { - for (comp.export_symbol_names.items) |symbol_name| { - try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name})); - } - } else { - const skip_export_non_fn = target.os.tag == .wasi and - wasm.base.options.wasi_exec_model == .command; - for (mod.decl_exports.values()) |exports| { - for (exports.items) |exprt| { - const exported_decl = mod.declPtr(exprt.exported_decl); - if (skip_export_non_fn and exported_decl.ty.zigTypeTag() != .Fn) { - // skip exporting symbols when we're building a WASI command - // and the symbol is not a function - continue; - } - const symbol_name = exported_decl.name; - const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); - try argv.append(arg); + const skip_export_non_fn = target.os.tag == .wasi and + wasm.base.options.wasi_exec_model == .command; + for (mod.decl_exports.values()) |exports| { + for (exports.items) |exprt| { + const exported_decl = mod.declPtr(exprt.exported_decl); + if (skip_export_non_fn and exported_decl.ty.zigTypeTag() != .Fn) { + // skip exporting symbols when we're building a WASI command + // and the symbol is not a function + continue; } + const symbol_name = exported_decl.name; + const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); + try argv.append(arg); } } } diff --git a/src/main.zig b/src/main.zig index 45d6b5bffc2f..c5da8e3a884e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -394,8 +394,6 @@ const usage_build_generic = \\ -fno-LLVM Prevent using LLVM as the codegen backend \\ -fClang Force using Clang as the C/C++ compilation backend \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ -fsingle-threaded Code assumes there is only one thread @@ -719,7 +717,6 @@ fn buildOutputType( var use_llvm: ?bool = null; var use_lld: ?bool = null; var use_clang: ?bool = null; - var use_stage1: ?bool = null; var link_eh_frame_hdr = false; var link_emit_relocs = false; var each_lib_rpath: ?bool = null; @@ -1158,10 +1155,6 @@ fn buildOutputType( use_clang = true; } else if (mem.eql(u8, arg, "-fno-Clang")) { use_clang = false; - } else if (mem.eql(u8, arg, "-fstage1")) { - use_stage1 = true; - } else if (mem.eql(u8, arg, "-fno-stage1")) { - use_stage1 = false; } else if (mem.eql(u8, arg, "-freference-trace")) { reference_trace = 256; } else if (mem.startsWith(u8, arg, "-freference-trace=")) { @@ -2909,7 +2902,6 @@ fn buildOutputType( .use_llvm = use_llvm, .use_lld = use_lld, .use_clang = use_clang, - .use_stage1 = use_stage1, .hash_style = hash_style, .rdynamic = rdynamic, .linker_script = linker_script, @@ -3024,8 +3016,7 @@ fn buildOutputType( return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena)); } if (arg_mode == .translate_c) { - const stage1_mode = use_stage1 orelse false; - return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode); + return cmdTranslateC(comp, arena, have_enable_cache); } const hook: AfterUpdateHook = blk: { @@ -3444,7 +3435,7 @@ fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void { } } -fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage1_mode: bool) !void { +fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void { if (!build_options.have_llvm) fatal("cannot translate-c: compiler built without LLVM extensions", .{}); @@ -3457,7 +3448,6 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage defer if (enable_cache) man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(stage1_mode); man.hashCSource(c_source_file) catch |err| { fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) }); }; @@ -3509,7 +3499,6 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage new_argv.ptr + new_argv.len, &clang_errors, c_headers_dir_path_z, - stage1_mode, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ASTUnitFailure => fatal("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}), @@ -3755,8 +3744,6 @@ pub const usage_build = \\ Build a project from build.zig. \\ \\Options: - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ --build-file [file] Override path to build.zig @@ -3770,7 +3757,6 @@ pub const usage_build = pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { var prominent_compile_errors: bool = false; - var use_stage1: ?bool = null; // We want to release all the locks before executing the child process, so we make a nice // big block here to ensure the cleanup gets run when we extract out our argv. @@ -3827,12 +3813,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi continue; } else if (mem.eql(u8, arg, "--prominent-compile-errors")) { prominent_compile_errors = true; - } else if (mem.eql(u8, arg, "-fstage1")) { - use_stage1 = true; - try child_argv.append(arg); - } else if (mem.eql(u8, arg, "-fno-stage1")) { - use_stage1 = false; - try child_argv.append(arg); } else if (mem.eql(u8, arg, "-freference-trace")) { try child_argv.append(arg); reference_trace = 256; @@ -3979,7 +3959,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi .optimize_mode = .Debug, .self_exe_path = self_exe_path, .thread_pool = &thread_pool, - .use_stage1 = use_stage1, .cache_mode = .whole, .reference_trace = reference_trace, .debug_compile_errors = debug_compile_errors, diff --git a/src/test.zig b/src/test.zig index ab70198e410d..de0efc359d78 100644 --- a/src/test.zig +++ b/src/test.zig @@ -1548,7 +1548,6 @@ pub const TestContext = struct { .dynamic_linker = target_info.dynamic_linker.get(), .link_libc = case.link_libc, .use_llvm = use_llvm, - .use_stage1 = null, // We already handled stage1 tests .self_exe_path = zig_exe_path, // TODO instead of turning off color, pass in a std.Progress.Node .color = .off, diff --git a/src/translate_c.zig b/src/translate_c.zig index 7a4bd843a58f..d4b2e0c709fc 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -327,16 +327,6 @@ pub const Context = struct { pattern_list: PatternList, - /// This is used to emit different code depending on whether - /// the output zig source code is intended to be compiled with stage1 or stage2. - /// Ideally we will have stage1 and stage2 support the exact same Zig language, - /// but for now they diverge because I would rather focus on finishing and shipping - /// stage2 than implementing the features in stage1. - /// The list of differences are currently: - /// * function pointers in stage1 are e.g. `fn()void` - /// but in stage2 they are `*const fn()void`. - zig_is_stage1: bool, - fn getMangle(c: *Context) u32 { c.mangle_count += 1; return c.mangle_count; @@ -365,7 +355,6 @@ pub fn translate( args_end: [*]?[*]const u8, errors: *[]ClangErrMsg, resources_path: [*:0]const u8, - zig_is_stage1: bool, ) !std.zig.Ast { // TODO stage2 bug var tmp = errors; @@ -395,7 +384,6 @@ pub fn translate( .global_scope = try arena.create(Scope.Root), .clang_context = ast_unit.getASTContext(), .pattern_list = try PatternList.init(gpa), - .zig_is_stage1 = zig_is_stage1, }; context.global_scope.* = Scope.Root.init(&context); defer { @@ -435,7 +423,7 @@ pub fn translate( } } - return ast.render(gpa, zig_is_stage1, context.global_scope.nodes.items); + return ast.render(gpa, context.global_scope.nodes.items); } /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) @@ -4747,9 +4735,6 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan .Pointer => { const child_qt = ty.getPointeeType(); const is_fn_proto = qualTypeChildIsFnProto(child_qt); - if (c.zig_is_stage1 and is_fn_proto) { - return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc)); - } const is_const = is_fn_proto or child_qt.isConstQualified(); const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, scope, child_qt, source_loc); @@ -6681,16 +6666,10 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { return null; if (getContainerTypeOf(c, init)) |ty_node| { if (ty_node.castTag(.optional_type)) |prefix| { - if (c.zig_is_stage1) { - if (prefix.data.castTag(.func)) |fn_proto| { + if (prefix.data.castTag(.single_pointer)) |sp| { + if (sp.data.elem_type.castTag(.func)) |fn_proto| { return fn_proto; } - } else { - if (prefix.data.castTag(.single_pointer)) |sp| { - if (sp.data.elem_type.castTag(.func)) |fn_proto| { - return fn_proto; - } - } } } } diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index bc0f002c2116..00f5481b9878 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -732,11 +732,10 @@ pub const Payload = struct { /// Converts the nodes into a Zig Ast. /// Caller must free the source slice. -pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig.Ast { +pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast { var ctx = Context{ .gpa = gpa, .buf = std.ArrayList(u8).init(gpa), - .zig_is_stage1 = zig_is_stage1, }; defer ctx.buf.deinit(); defer ctx.nodes.deinit(gpa); @@ -805,11 +804,6 @@ const Context = struct { extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, tokens: std.zig.Ast.TokenList = .{}, - /// This is used to emit different code depending on whether - /// the output zig source code is intended to be compiled with stage1 or stage2. - /// Refer to the Context in translate_c.zig. - zig_is_stage1: bool, - fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { const start_index = c.buf.items.len; try c.buf.writer().print(format ++ " ", args); @@ -932,7 +926,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .call => { const payload = node.castTag(.call).?.data; // Cosmetic: avoids an unnecesary address_of on most function calls. - const lhs = if (!c.zig_is_stage1 and payload.lhs.tag() == .fn_identifier) + const lhs = if (payload.lhs.tag() == .fn_identifier) try c.addNode(.{ .tag = .identifier, .main_token = try c.addIdentifier(payload.lhs.castTag(.fn_identifier).?.data), @@ -1097,28 +1091,20 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { // value (implicit in stage1, explicit in stage2), except in // the context of an address_of, which is handled there. const payload = node.castTag(.fn_identifier).?.data; - if (c.zig_is_stage1) { - return try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload), - .data = undefined, - }); - } else { - const tok = try c.addToken(.ampersand, "&"); - const arg = try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload), - .data = undefined, - }); - return c.addNode(.{ - .tag = .address_of, - .main_token = tok, - .data = .{ - .lhs = arg, - .rhs = undefined, - }, - }); - } + const tok = try c.addToken(.ampersand, "&"); + const arg = try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload), + .data = undefined, + }); + return c.addNode(.{ + .tag = .address_of, + .main_token = tok, + .data = .{ + .lhs = arg, + .rhs = undefined, + }, + }); }, .float_literal => { const payload = node.castTag(.float_literal).?.data; @@ -1448,7 +1434,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"), .address_of => { const payload = node.castTag(.address_of).?.data; - if (c.zig_is_stage1 and payload.tag() == .fn_identifier) + if (payload.tag() == .fn_identifier) return try c.addNode(.{ .tag = .identifier, .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig index 5ac97c9cef5a..7efa88999ad8 100644 --- a/test/link/wasm/archive/build.zig +++ b/test/link/wasm/archive/build.zig @@ -13,7 +13,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index 0a8d652338c2..c9bc1aa1069a 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; // to make sure the bss segment is emitted, we must import memory diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig index 0f29c6896836..7557b4fa4144 100644 --- a/test/link/wasm/producers/build.zig +++ b/test/link/wasm/producers/build.zig @@ -12,7 +12,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig index 06ca55300fbb..1b2cdf87ab4f 100644 --- a/test/link/wasm/segments/build.zig +++ b/test/link/wasm/segments/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig index 1f50a60d1989..5b67c3caa3f4 100644 --- a/test/link/wasm/stack_pointer/build.zig +++ b/test/link/wasm/stack_pointer/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.stack_size = std.wasm.page_size * 2; // set an explicit stack size diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig index 2c926eced3e5..fbae6dc741da 100644 --- a/test/link/wasm/type/build.zig +++ b/test/link/wasm/type/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/tests.zig b/test/tests.zig index b738de86b0ad..0817a541d953 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -720,20 +720,18 @@ pub fn addPkgTests( these_tests.addIncludePath("test"); if (test_target.backend) |backend| switch (backend) { .stage1 => { - these_tests.use_stage1 = true; + @panic("stage1 testing requested"); }, .stage2_llvm => { - these_tests.use_stage1 = false; these_tests.use_llvm = true; }, .stage2_c => { - these_tests.use_stage1 = false; these_tests.use_llvm = false; }, else => { - these_tests.use_stage1 = false; these_tests.use_llvm = false; - // TODO: force self-hosted linkers to avoid LLD creeping in until the auto-select mechanism deems them worthy + // TODO: force self-hosted linkers to avoid LLD creeping in + // until the auto-select mechanism deems them worthy these_tests.use_lld = false; }, }; @@ -1355,8 +1353,6 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step { triple_prefix, })); - test_step.use_stage1 = false; - step.dependOn(&test_step.step); } return step; From db023b98a4deef527d4c70d146009f754e9b168d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 4 Nov 2022 18:35:04 -0700 Subject: [PATCH 02/68] build: introduce -Dwasi-bootstrap option Also, make -Donly-c prevent Autodoc from being included in the binary. This produces a 2.6 MiB zig.wasm file. 781 KB if piped through zstd. --- build.zig | 39 +++++++++++++++++++++++++-------------- src/Compilation.zig | 12 +++++++----- src/main.zig | 8 +++++++- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/build.zig b/build.zig index adab2b241177..8560e5e2d2ca 100644 --- a/build.zig +++ b/build.zig @@ -14,13 +14,30 @@ const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 }; const stack_size = 32 * 1024 * 1024; pub fn build(b: *Builder) !void { - b.setPreferredReleaseMode(.ReleaseFast); - const test_step = b.step("test", "Run all the tests"); - const mode = b.standardReleaseOptions(); - var target = b.standardTargetOptions(.{}); + const wasi_bootstrap = b.option(bool, "wasi-bootstrap", "Produce a WASI build for bootstrapping the compiler") orelse false; + const release = b.option(bool, "release", "Build in release mode") orelse wasi_bootstrap; + const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse wasi_bootstrap; + const target = t: { + var default_target: std.zig.CrossTarget = .{}; + if (wasi_bootstrap) { + default_target.cpu_arch = .wasm32; + default_target.os_tag = .wasi; + break :t default_target; + } else if (only_c) { + default_target.ofmt = .c; + } + break :t b.standardTargetOptions(.{ .default_target = default_target }); + }; + const mode: std.builtin.Mode = if (release) switch (target.getCpuArch()) { + .wasm32 => .ReleaseSmall, + else => .ReleaseFast, + } else .Debug; + const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false; + const test_step = b.step("test", "Run all the tests"); + const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); docgen_exe.single_threaded = single_threaded; @@ -48,8 +65,6 @@ pub fn build(b: *Builder) !void { const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); - const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; - const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; @@ -65,7 +80,7 @@ pub fn build(b: *Builder) !void { if (deprecated_skip_install_lib_files) { std.log.warn("-Dskip-install-lib-files is deprecated in favor of -Dno-lib", .{}); } - const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files to installation prefix. Useful for development") orelse deprecated_skip_install_lib_files; + const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files to installation prefix. Useful for development") orelse (deprecated_skip_install_lib_files or wasi_bootstrap); const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; @@ -129,21 +144,17 @@ pub fn build(b: *Builder) !void { const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false; - const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); + const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or (only_c and !wasi_bootstrap)); const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; - const strip = b.option(bool, "strip", "Omit debug information") orelse false; + const strip = b.option(bool, "strip", "Omit debug information"); const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { - if (strip) break :blk @as(u32, 0); + if (strip == true) break :blk @as(u32, 0); if (mode != .Debug) break :blk 0; break :blk 4; }; - if (only_c) { - target.ofmt = .c; - } - const main_file: ?[]const u8 = "src/main.zig"; const exe = b.addExecutable("zig", main_file); diff --git a/src/Compilation.zig b/src/Compilation.zig index a0b78394e711..853d83485a77 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2421,11 +2421,13 @@ pub fn update(comp: *Compilation) !void { return; } - if (comp.emit_docs) |doc_location| { - if (comp.bin_file.options.module) |module| { - var autodoc = Autodoc.init(module, doc_location); - defer autodoc.deinit(); - try autodoc.generateZirData(); + if (!build_options.only_c) { + if (comp.emit_docs) |doc_location| { + if (comp.bin_file.options.module) |module| { + var autodoc = Autodoc.init(module, doc_location); + defer autodoc.deinit(); + try autodoc.generateZirData(); + } } } diff --git a/src/main.zig b/src/main.zig index c5da8e3a884e..5947ff773aa4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -168,7 +168,13 @@ pub fn main() anyerror!void { // This sets our CWD to "/preopens/cwd" // Dot-prefixed preopens like `--dir=.` are "mounted" at "/preopens/cwd" // Other preopens like `--dir=lib` are "mounted" at "/" - try std.os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd"); + try std.os.initPreopensWasi(arena, "/preopens/cwd"); + } + + // Short circuit some of the other logic for bootstrapping. + if (build_options.only_c) { + assert(mem.eql(u8, args[1], "build-obj")); + return buildOutputType(gpa, arena, args, .{ .build = .Obj }); } return mainArgs(gpa, arena, args); From 4e2a960b523070c7f8fddf0ea9b6e2a94e31dafe Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 9 Nov 2022 14:44:34 -0700 Subject: [PATCH 03/68] std.fs: fix openDirAbsolute These functions had a compile error since the introduction of IterableDir. --- lib/std/fs.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 8ae21259ae1d..12ee39a7bf43 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2685,12 +2685,12 @@ pub fn openDirAbsolute(absolute_path: []const u8, flags: Dir.OpenDirOptions) Fil /// Same as `openDirAbsolute` but the path parameter is null-terminated. pub fn openDirAbsoluteZ(absolute_path_c: [*:0]const u8, flags: Dir.OpenDirOptions) File.OpenError!Dir { assert(path.isAbsoluteZ(absolute_path_c)); - return cwd().openDirZ(absolute_path_c, flags); + return cwd().openDirZ(absolute_path_c, flags, false); } /// Same as `openDirAbsolute` but the path parameter is null-terminated. pub fn openDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptions) File.OpenError!Dir { assert(path.isAbsoluteWindowsW(absolute_path_c)); - return cwd().openDirW(absolute_path_c, flags); + return cwd().openDirW(absolute_path_c, flags, false); } /// Opens a directory at the given path. The directory is a system resource that remains From 3ba916584db5485c38ebf2390e8d22bc6d81bf8e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 4 Nov 2022 18:47:19 -0700 Subject: [PATCH 04/68] actually remove stage1 --- deps/SoftFloat-3e-prebuilt/platform.h | 99 - deps/SoftFloat-3e/COPYING.txt | 37 - deps/SoftFloat-3e/README.html | 49 - deps/SoftFloat-3e/README.txt | 21 - deps/SoftFloat-3e/doc/SoftFloat-history.html | 258 - deps/SoftFloat-3e/doc/SoftFloat-source.html | 686 - deps/SoftFloat-3e/doc/SoftFloat.html | 1527 - .../source/8086-SSE/extF80M_isSignalingNaN.c | 57 - .../source/8086-SSE/f128M_isSignalingNaN.c | 60 - .../source/8086-SSE/s_commonNaNToExtF80M.c | 56 - .../source/8086-SSE/s_commonNaNToExtF80UI.c | 56 - .../source/8086-SSE/s_commonNaNToF128M.c | 56 - .../source/8086-SSE/s_commonNaNToF128UI.c | 55 - .../source/8086-SSE/s_commonNaNToF16UI.c | 51 - .../source/8086-SSE/s_commonNaNToF32UI.c | 51 - .../source/8086-SSE/s_commonNaNToF64UI.c | 53 - .../source/8086-SSE/s_extF80MToCommonNaN.c | 62 - .../source/8086-SSE/s_extF80UIToCommonNaN.c | 62 - .../source/8086-SSE/s_f128MToCommonNaN.c | 62 - .../source/8086-SSE/s_f128UIToCommonNaN.c | 65 - .../source/8086-SSE/s_f16UIToCommonNaN.c | 59 - .../source/8086-SSE/s_f32UIToCommonNaN.c | 59 - .../source/8086-SSE/s_f64UIToCommonNaN.c | 59 - .../source/8086-SSE/s_propagateNaNExtF80M.c | 107 - .../source/8086-SSE/s_propagateNaNExtF80UI.c | 106 - .../source/8086-SSE/s_propagateNaNF128M.c | 76 - .../source/8086-SSE/s_propagateNaNF128UI.c | 81 - .../source/8086-SSE/s_propagateNaNF16UI.c | 63 - .../source/8086-SSE/s_propagateNaNF32UI.c | 63 - .../source/8086-SSE/s_propagateNaNF64UI.c | 63 - .../source/8086-SSE/softfloat_raiseFlags.c | 52 - .../SoftFloat-3e/source/8086-SSE/specialize.h | 376 - .../source/8086/extF80M_isSignalingNaN.c | 57 - .../source/8086/f128M_isSignalingNaN.c | 60 - .../source/8086/s_commonNaNToExtF80M.c | 56 - .../source/8086/s_commonNaNToExtF80UI.c | 56 - .../source/8086/s_commonNaNToF128M.c | 56 - .../source/8086/s_commonNaNToF128UI.c | 55 - .../source/8086/s_commonNaNToF16UI.c | 51 - .../source/8086/s_commonNaNToF32UI.c | 51 - .../source/8086/s_commonNaNToF64UI.c | 53 - .../source/8086/s_extF80MToCommonNaN.c | 62 - .../source/8086/s_extF80UIToCommonNaN.c | 62 - .../source/8086/s_f128MToCommonNaN.c | 62 - .../source/8086/s_f128UIToCommonNaN.c | 65 - .../source/8086/s_f16UIToCommonNaN.c | 59 - .../source/8086/s_f32UIToCommonNaN.c | 59 - .../source/8086/s_f64UIToCommonNaN.c | 59 - .../source/8086/s_propagateNaNExtF80M.c | 107 - .../source/8086/s_propagateNaNExtF80UI.c | 106 - .../source/8086/s_propagateNaNF128M.c | 108 - .../source/8086/s_propagateNaNF128UI.c | 105 - .../source/8086/s_propagateNaNF16UI.c | 84 - .../source/8086/s_propagateNaNF32UI.c | 84 - .../source/8086/s_propagateNaNF64UI.c | 84 - .../source/8086/softfloat_raiseFlags.c | 52 - deps/SoftFloat-3e/source/8086/specialize.h | 376 - .../extF80M_isSignalingNaN.c | 57 - .../f128M_isSignalingNaN.c | 60 - .../s_commonNaNToExtF80M.c | 57 - .../s_commonNaNToExtF80UI.c | 57 - .../ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c | 60 - .../s_commonNaNToF128UI.c | 56 - .../ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c | 5 - .../ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c | 5 - .../ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c | 5 - .../s_extF80MToCommonNaN.c | 5 - .../s_extF80UIToCommonNaN.c | 5 - .../ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c | 5 - .../s_f128UIToCommonNaN.c | 5 - .../ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c | 5 - .../ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c | 5 - .../ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c | 5 - .../s_propagateNaNExtF80M.c | 74 - .../s_propagateNaNExtF80UI.c | 73 - .../s_propagateNaNF128M.c | 68 - .../s_propagateNaNF128UI.c | 73 - .../s_propagateNaNF16UI.c | 58 - .../s_propagateNaNF32UI.c | 58 - .../s_propagateNaNF64UI.c | 58 - .../softfloat_raiseFlags.c | 52 - .../source/ARM-VFPv2-defaultNaN/specialize.h | 407 - .../source/ARM-VFPv2/extF80M_isSignalingNaN.c | 57 - .../source/ARM-VFPv2/f128M_isSignalingNaN.c | 60 - .../source/ARM-VFPv2/s_commonNaNToExtF80M.c | 56 - .../source/ARM-VFPv2/s_commonNaNToExtF80UI.c | 56 - .../source/ARM-VFPv2/s_commonNaNToF128M.c | 56 - .../source/ARM-VFPv2/s_commonNaNToF128UI.c | 55 - .../source/ARM-VFPv2/s_commonNaNToF16UI.c | 51 - .../source/ARM-VFPv2/s_commonNaNToF32UI.c | 51 - .../source/ARM-VFPv2/s_commonNaNToF64UI.c | 53 - .../source/ARM-VFPv2/s_extF80MToCommonNaN.c | 62 - .../source/ARM-VFPv2/s_extF80UIToCommonNaN.c | 62 - .../source/ARM-VFPv2/s_f128MToCommonNaN.c | 62 - .../source/ARM-VFPv2/s_f128UIToCommonNaN.c | 65 - .../source/ARM-VFPv2/s_f16UIToCommonNaN.c | 59 - .../source/ARM-VFPv2/s_f32UIToCommonNaN.c | 59 - .../source/ARM-VFPv2/s_f64UIToCommonNaN.c | 59 - .../source/ARM-VFPv2/s_propagateNaNExtF80M.c | 86 - .../source/ARM-VFPv2/s_propagateNaNExtF80UI.c | 83 - .../source/ARM-VFPv2/s_propagateNaNF128M.c | 77 - .../source/ARM-VFPv2/s_propagateNaNF128UI.c | 83 - .../source/ARM-VFPv2/s_propagateNaNF16UI.c | 63 - .../source/ARM-VFPv2/s_propagateNaNF32UI.c | 63 - .../source/ARM-VFPv2/s_propagateNaNF64UI.c | 63 - .../source/ARM-VFPv2/softfloat_raiseFlags.c | 52 - .../source/ARM-VFPv2/specialize.h | 376 - deps/SoftFloat-3e/source/extF80M_add.c | 100 - deps/SoftFloat-3e/source/extF80M_div.c | 194 - deps/SoftFloat-3e/source/extF80M_eq.c | 98 - .../source/extF80M_eq_signaling.c | 92 - deps/SoftFloat-3e/source/extF80M_le.c | 106 - deps/SoftFloat-3e/source/extF80M_le_quiet.c | 112 - deps/SoftFloat-3e/source/extF80M_lt.c | 106 - deps/SoftFloat-3e/source/extF80M_lt_quiet.c | 112 - deps/SoftFloat-3e/source/extF80M_mul.c | 139 - deps/SoftFloat-3e/source/extF80M_rem.c | 204 - deps/SoftFloat-3e/source/extF80M_roundToInt.c | 176 - deps/SoftFloat-3e/source/extF80M_sqrt.c | 180 - deps/SoftFloat-3e/source/extF80M_sub.c | 100 - deps/SoftFloat-3e/source/extF80M_to_f128M.c | 125 - deps/SoftFloat-3e/source/extF80M_to_f16.c | 112 - deps/SoftFloat-3e/source/extF80M_to_f32.c | 112 - deps/SoftFloat-3e/source/extF80M_to_f64.c | 112 - deps/SoftFloat-3e/source/extF80M_to_i32.c | 100 - .../source/extF80M_to_i32_r_minMag.c | 120 - deps/SoftFloat-3e/source/extF80M_to_i64.c | 97 - .../source/extF80M_to_i64_r_minMag.c | 115 - deps/SoftFloat-3e/source/extF80M_to_ui32.c | 101 - .../source/extF80M_to_ui32_r_minMag.c | 111 - deps/SoftFloat-3e/source/extF80M_to_ui64.c | 97 - .../source/extF80M_to_ui64_r_minMag.c | 108 - deps/SoftFloat-3e/source/extF80_add.c | 80 - deps/SoftFloat-3e/source/extF80_div.c | 203 - deps/SoftFloat-3e/source/extF80_eq.c | 73 - .../SoftFloat-3e/source/extF80_eq_signaling.c | 67 - .../source/extF80_isSignalingNaN.c | 51 - deps/SoftFloat-3e/source/extF80_le.c | 73 - deps/SoftFloat-3e/source/extF80_le_quiet.c | 78 - deps/SoftFloat-3e/source/extF80_lt.c | 73 - deps/SoftFloat-3e/source/extF80_lt_quiet.c | 78 - deps/SoftFloat-3e/source/extF80_mul.c | 158 - deps/SoftFloat-3e/source/extF80_rem.c | 225 - deps/SoftFloat-3e/source/extF80_roundToInt.c | 154 - deps/SoftFloat-3e/source/extF80_sqrt.c | 176 - deps/SoftFloat-3e/source/extF80_sub.c | 80 - deps/SoftFloat-3e/source/extF80_to_f128.c | 75 - deps/SoftFloat-3e/source/extF80_to_f16.c | 96 - deps/SoftFloat-3e/source/extF80_to_f32.c | 96 - deps/SoftFloat-3e/source/extF80_to_f64.c | 96 - deps/SoftFloat-3e/source/extF80_to_i32.c | 83 - .../source/extF80_to_i32_r_minMag.c | 97 - deps/SoftFloat-3e/source/extF80_to_i64.c | 89 - .../source/extF80_to_i64_r_minMag.c | 94 - deps/SoftFloat-3e/source/extF80_to_ui32.c | 83 - .../source/extF80_to_ui32_r_minMag.c | 88 - deps/SoftFloat-3e/source/extF80_to_ui64.c | 84 - .../source/extF80_to_ui64_r_minMag.c | 88 - deps/SoftFloat-3e/source/f128M_add.c | 97 - deps/SoftFloat-3e/source/f128M_div.c | 187 - deps/SoftFloat-3e/source/f128M_eq.c | 100 - deps/SoftFloat-3e/source/f128M_eq_signaling.c | 92 - deps/SoftFloat-3e/source/f128M_le.c | 93 - deps/SoftFloat-3e/source/f128M_le_quiet.c | 96 - deps/SoftFloat-3e/source/f128M_lt.c | 93 - deps/SoftFloat-3e/source/f128M_lt_quiet.c | 96 - deps/SoftFloat-3e/source/f128M_mul.c | 158 - deps/SoftFloat-3e/source/f128M_mulAdd.c | 92 - deps/SoftFloat-3e/source/f128M_rem.c | 182 - deps/SoftFloat-3e/source/f128M_roundToInt.c | 223 - deps/SoftFloat-3e/source/f128M_sqrt.c | 228 - deps/SoftFloat-3e/source/f128M_sub.c | 97 - deps/SoftFloat-3e/source/f128M_to_extF80M.c | 101 - deps/SoftFloat-3e/source/f128M_to_f16.c | 113 - deps/SoftFloat-3e/source/f128M_to_f32.c | 109 - deps/SoftFloat-3e/source/f128M_to_f64.c | 112 - deps/SoftFloat-3e/source/f128M_to_i32.c | 98 - .../source/f128M_to_i32_r_minMag.c | 106 - deps/SoftFloat-3e/source/f128M_to_i64.c | 102 - .../source/f128M_to_i64_r_minMag.c | 124 - deps/SoftFloat-3e/source/f128M_to_ui32.c | 98 - .../source/f128M_to_ui32_r_minMag.c | 102 - deps/SoftFloat-3e/source/f128M_to_ui64.c | 102 - .../source/f128M_to_ui64_r_minMag.c | 114 - deps/SoftFloat-3e/source/f128_add.c | 78 - deps/SoftFloat-3e/source/f128_div.c | 199 - deps/SoftFloat-3e/source/f128_eq.c | 73 - deps/SoftFloat-3e/source/f128_eq_signaling.c | 67 - .../SoftFloat-3e/source/f128_isSignalingNaN.c | 51 - deps/SoftFloat-3e/source/f128_le.c | 72 - deps/SoftFloat-3e/source/f128_le_quiet.c | 78 - deps/SoftFloat-3e/source/f128_lt.c | 72 - deps/SoftFloat-3e/source/f128_lt_quiet.c | 78 - deps/SoftFloat-3e/source/f128_mul.c | 163 - deps/SoftFloat-3e/source/f128_mulAdd.c | 63 - deps/SoftFloat-3e/source/f128_rem.c | 190 - deps/SoftFloat-3e/source/f128_roundToInt.c | 172 - deps/SoftFloat-3e/source/f128_sqrt.c | 201 - deps/SoftFloat-3e/source/f128_sub.c | 78 - deps/SoftFloat-3e/source/f128_to_extF80.c | 109 - deps/SoftFloat-3e/source/f128_to_f16.c | 95 - deps/SoftFloat-3e/source/f128_to_f32.c | 95 - deps/SoftFloat-3e/source/f128_to_f64.c | 100 - deps/SoftFloat-3e/source/f128_to_i32.c | 85 - .../source/f128_to_i32_r_minMag.c | 100 - deps/SoftFloat-3e/source/f128_to_i64.c | 95 - .../source/f128_to_i64_r_minMag.c | 113 - deps/SoftFloat-3e/source/f128_to_ui32.c | 86 - .../source/f128_to_ui32_r_minMag.c | 89 - deps/SoftFloat-3e/source/f128_to_ui64.c | 96 - .../source/f128_to_ui64_r_minMag.c | 105 - deps/SoftFloat-3e/source/f16_add.c | 70 - deps/SoftFloat-3e/source/f16_div.c | 186 - deps/SoftFloat-3e/source/f16_eq.c | 66 - deps/SoftFloat-3e/source/f16_eq_signaling.c | 61 - deps/SoftFloat-3e/source/f16_isSignalingNaN.c | 51 - deps/SoftFloat-3e/source/f16_le.c | 66 - deps/SoftFloat-3e/source/f16_le_quiet.c | 71 - deps/SoftFloat-3e/source/f16_lt.c | 66 - deps/SoftFloat-3e/source/f16_lt_quiet.c | 71 - deps/SoftFloat-3e/source/f16_mul.c | 140 - deps/SoftFloat-3e/source/f16_mulAdd.c | 60 - deps/SoftFloat-3e/source/f16_rem.c | 171 - deps/SoftFloat-3e/source/f16_roundToInt.c | 120 - deps/SoftFloat-3e/source/f16_sqrt.c | 136 - deps/SoftFloat-3e/source/f16_sub.c | 70 - deps/SoftFloat-3e/source/f16_to_extF80.c | 101 - deps/SoftFloat-3e/source/f16_to_extF80M.c | 111 - deps/SoftFloat-3e/source/f16_to_f128.c | 96 - deps/SoftFloat-3e/source/f16_to_f128M.c | 111 - deps/SoftFloat-3e/source/f16_to_f32.c | 93 - deps/SoftFloat-3e/source/f16_to_f64.c | 93 - deps/SoftFloat-3e/source/f16_to_i32.c | 87 - .../SoftFloat-3e/source/f16_to_i32_r_minMag.c | 88 - deps/SoftFloat-3e/source/f16_to_i64.c | 87 - .../SoftFloat-3e/source/f16_to_i64_r_minMag.c | 88 - deps/SoftFloat-3e/source/f16_to_ui32.c | 84 - .../source/f16_to_ui32_r_minMag.c | 87 - deps/SoftFloat-3e/source/f16_to_ui64.c | 96 - .../source/f16_to_ui64_r_minMag.c | 87 - deps/SoftFloat-3e/source/f32_add.c | 70 - deps/SoftFloat-3e/source/f32_div.c | 180 - deps/SoftFloat-3e/source/f32_eq.c | 66 - deps/SoftFloat-3e/source/f32_eq_signaling.c | 61 - deps/SoftFloat-3e/source/f32_isSignalingNaN.c | 51 - deps/SoftFloat-3e/source/f32_le.c | 66 - deps/SoftFloat-3e/source/f32_le_quiet.c | 71 - deps/SoftFloat-3e/source/f32_lt.c | 66 - deps/SoftFloat-3e/source/f32_lt_quiet.c | 71 - deps/SoftFloat-3e/source/f32_mul.c | 137 - deps/SoftFloat-3e/source/f32_mulAdd.c | 60 - deps/SoftFloat-3e/source/f32_rem.c | 168 - deps/SoftFloat-3e/source/f32_roundToInt.c | 120 - deps/SoftFloat-3e/source/f32_sqrt.c | 121 - deps/SoftFloat-3e/source/f32_sub.c | 70 - deps/SoftFloat-3e/source/f32_to_extF80.c | 101 - deps/SoftFloat-3e/source/f32_to_extF80M.c | 111 - deps/SoftFloat-3e/source/f32_to_f128.c | 96 - deps/SoftFloat-3e/source/f32_to_f128M.c | 115 - deps/SoftFloat-3e/source/f32_to_f16.c | 88 - deps/SoftFloat-3e/source/f32_to_f64.c | 93 - deps/SoftFloat-3e/source/f32_to_i32.c | 84 - .../SoftFloat-3e/source/f32_to_i32_r_minMag.c | 89 - deps/SoftFloat-3e/source/f32_to_i64.c | 96 - .../SoftFloat-3e/source/f32_to_i64_r_minMag.c | 94 - deps/SoftFloat-3e/source/f32_to_ui32.c | 84 - .../source/f32_to_ui32_r_minMag.c | 88 - deps/SoftFloat-3e/source/f32_to_ui64.c | 96 - .../source/f32_to_ui64_r_minMag.c | 90 - deps/SoftFloat-3e/source/f64_add.c | 74 - deps/SoftFloat-3e/source/f64_div.c | 172 - deps/SoftFloat-3e/source/f64_eq.c | 66 - deps/SoftFloat-3e/source/f64_eq_signaling.c | 61 - deps/SoftFloat-3e/source/f64_isSignalingNaN.c | 51 - deps/SoftFloat-3e/source/f64_le.c | 67 - deps/SoftFloat-3e/source/f64_le_quiet.c | 72 - deps/SoftFloat-3e/source/f64_lt.c | 67 - deps/SoftFloat-3e/source/f64_lt_quiet.c | 72 - deps/SoftFloat-3e/source/f64_mul.c | 150 - deps/SoftFloat-3e/source/f64_mulAdd.c | 60 - deps/SoftFloat-3e/source/f64_rem.c | 189 - deps/SoftFloat-3e/source/f64_roundToInt.c | 120 - deps/SoftFloat-3e/source/f64_sqrt.c | 133 - deps/SoftFloat-3e/source/f64_sub.c | 74 - deps/SoftFloat-3e/source/f64_to_extF80.c | 101 - deps/SoftFloat-3e/source/f64_to_extF80M.c | 111 - deps/SoftFloat-3e/source/f64_to_f128.c | 98 - deps/SoftFloat-3e/source/f64_to_f128M.c | 117 - deps/SoftFloat-3e/source/f64_to_f16.c | 88 - deps/SoftFloat-3e/source/f64_to_f32.c | 88 - deps/SoftFloat-3e/source/f64_to_i32.c | 82 - .../SoftFloat-3e/source/f64_to_i32_r_minMag.c | 96 - deps/SoftFloat-3e/source/f64_to_i64.c | 103 - .../SoftFloat-3e/source/f64_to_i64_r_minMag.c | 100 - deps/SoftFloat-3e/source/f64_to_ui32.c | 82 - .../source/f64_to_ui32_r_minMag.c | 88 - deps/SoftFloat-3e/source/f64_to_ui64.c | 103 - .../source/f64_to_ui64_r_minMag.c | 93 - deps/SoftFloat-3e/source/i32_to_extF80.c | 65 - deps/SoftFloat-3e/source/i32_to_extF80M.c | 78 - deps/SoftFloat-3e/source/i32_to_f128.c | 64 - deps/SoftFloat-3e/source/i32_to_f128M.c | 81 - deps/SoftFloat-3e/source/i32_to_f16.c | 71 - deps/SoftFloat-3e/source/i32_to_f32.c | 58 - deps/SoftFloat-3e/source/i32_to_f64.c | 65 - deps/SoftFloat-3e/source/i64_to_extF80.c | 65 - deps/SoftFloat-3e/source/i64_to_extF80M.c | 78 - deps/SoftFloat-3e/source/i64_to_f128.c | 72 - deps/SoftFloat-3e/source/i64_to_f128M.c | 92 - deps/SoftFloat-3e/source/i64_to_f16.c | 70 - deps/SoftFloat-3e/source/i64_to_f32.c | 70 - deps/SoftFloat-3e/source/i64_to_f64.c | 58 - deps/SoftFloat-3e/source/include/internals.h | 278 - deps/SoftFloat-3e/source/include/opts-GCC.h | 114 - .../source/include/primitiveTypes.h | 86 - deps/SoftFloat-3e/source/include/primitives.h | 1160 - deps/SoftFloat-3e/source/include/softfloat.h | 372 - .../source/include/softfloat_types.h | 82 - deps/SoftFloat-3e/source/s_add128.c | 55 - deps/SoftFloat-3e/source/s_add256M.c | 65 - deps/SoftFloat-3e/source/s_addCarryM.c | 70 - deps/SoftFloat-3e/source/s_addComplCarryM.c | 70 - deps/SoftFloat-3e/source/s_addExtF80M.c | 186 - deps/SoftFloat-3e/source/s_addF128M.c | 211 - deps/SoftFloat-3e/source/s_addM.c | 70 - deps/SoftFloat-3e/source/s_addMagsExtF80.c | 156 - deps/SoftFloat-3e/source/s_addMagsF128.c | 154 - deps/SoftFloat-3e/source/s_addMagsF16.c | 183 - deps/SoftFloat-3e/source/s_addMagsF32.c | 126 - deps/SoftFloat-3e/source/s_addMagsF64.c | 128 - deps/SoftFloat-3e/source/s_approxRecip32_1.c | 66 - .../source/s_approxRecipSqrt32_1.c | 73 - .../source/s_approxRecipSqrt_1Ks.c | 49 - deps/SoftFloat-3e/source/s_approxRecip_1Ks.c | 49 - deps/SoftFloat-3e/source/s_compare128M.c | 62 - deps/SoftFloat-3e/source/s_compare96M.c | 62 - .../source/s_compareNonnormExtF80M.c | 111 - .../source/s_countLeadingZeros16.c | 60 - .../source/s_countLeadingZeros32.c | 64 - .../source/s_countLeadingZeros64.c | 73 - .../source/s_countLeadingZeros8.c | 59 - deps/SoftFloat-3e/source/s_eq128.c | 51 - deps/SoftFloat-3e/source/s_invalidExtF80M.c | 49 - deps/SoftFloat-3e/source/s_invalidF128M.c | 53 - deps/SoftFloat-3e/source/s_isNaNF128M.c | 57 - deps/SoftFloat-3e/source/s_le128.c | 51 - deps/SoftFloat-3e/source/s_lt128.c | 51 - deps/SoftFloat-3e/source/s_mul128By32.c | 58 - deps/SoftFloat-3e/source/s_mul128MTo256M.c | 100 - deps/SoftFloat-3e/source/s_mul128To256M.c | 71 - .../source/s_mul64ByShifted32To128.c | 56 - deps/SoftFloat-3e/source/s_mul64To128.c | 66 - deps/SoftFloat-3e/source/s_mul64To128M.c | 68 - deps/SoftFloat-3e/source/s_mulAddF128.c | 350 - deps/SoftFloat-3e/source/s_mulAddF128M.c | 382 - deps/SoftFloat-3e/source/s_mulAddF16.c | 226 - deps/SoftFloat-3e/source/s_mulAddF32.c | 224 - deps/SoftFloat-3e/source/s_mulAddF64.c | 496 - deps/SoftFloat-3e/source/s_negXM.c | 63 - deps/SoftFloat-3e/source/s_normExtF80SigM.c | 52 - .../source/s_normRoundPackMToExtF80M.c | 78 - .../source/s_normRoundPackMToF128M.c | 73 - .../source/s_normRoundPackToExtF80.c | 71 - .../source/s_normRoundPackToF128.c | 81 - .../source/s_normRoundPackToF16.c | 58 - .../source/s_normRoundPackToF32.c | 58 - .../source/s_normRoundPackToF64.c | 58 - .../source/s_normSubnormalExtF80Sig.c | 52 - .../source/s_normSubnormalF128Sig.c | 65 - .../source/s_normSubnormalF128SigM.c | 61 - .../source/s_normSubnormalF16Sig.c | 52 - .../source/s_normSubnormalF32Sig.c | 52 - .../source/s_normSubnormalF64Sig.c | 52 - deps/SoftFloat-3e/source/s_remStepMBy32.c | 86 - deps/SoftFloat-3e/source/s_roundMToI64.c | 102 - deps/SoftFloat-3e/source/s_roundMToUI64.c | 98 - .../source/s_roundPackMToExtF80M.c | 256 - .../SoftFloat-3e/source/s_roundPackMToF128M.c | 178 - .../SoftFloat-3e/source/s_roundPackToExtF80.c | 256 - deps/SoftFloat-3e/source/s_roundPackToF128.c | 171 - deps/SoftFloat-3e/source/s_roundPackToF16.c | 113 - deps/SoftFloat-3e/source/s_roundPackToF32.c | 113 - deps/SoftFloat-3e/source/s_roundPackToF64.c | 117 - deps/SoftFloat-3e/source/s_roundToI32.c | 98 - deps/SoftFloat-3e/source/s_roundToI64.c | 101 - deps/SoftFloat-3e/source/s_roundToUI32.c | 93 - deps/SoftFloat-3e/source/s_roundToUI64.c | 97 - deps/SoftFloat-3e/source/s_shiftLeftM.c | 91 - .../SoftFloat-3e/source/s_shiftNormSigF128M.c | 78 - deps/SoftFloat-3e/source/s_shiftRightJam128.c | 69 - .../source/s_shiftRightJam128Extra.c | 77 - .../SoftFloat-3e/source/s_shiftRightJam256M.c | 126 - deps/SoftFloat-3e/source/s_shiftRightJam32.c | 51 - deps/SoftFloat-3e/source/s_shiftRightJam64.c | 51 - .../source/s_shiftRightJam64Extra.c | 62 - deps/SoftFloat-3e/source/s_shiftRightJamM.c | 101 - deps/SoftFloat-3e/source/s_shiftRightM.c | 91 - .../SoftFloat-3e/source/s_shortShiftLeft128.c | 55 - .../source/s_shortShiftLeft64To96M.c | 56 - deps/SoftFloat-3e/source/s_shortShiftLeftM.c | 70 - .../source/s_shortShiftRight128.c | 55 - .../source/s_shortShiftRightExtendM.c | 73 - .../source/s_shortShiftRightJam128.c | 60 - .../source/s_shortShiftRightJam128Extra.c | 59 - .../source/s_shortShiftRightJam64.c | 50 - .../source/s_shortShiftRightJam64Extra.c | 56 - .../source/s_shortShiftRightJamM.c | 72 - deps/SoftFloat-3e/source/s_shortShiftRightM.c | 70 - deps/SoftFloat-3e/source/s_sub128.c | 55 - deps/SoftFloat-3e/source/s_sub1XM.c | 60 - deps/SoftFloat-3e/source/s_sub256M.c | 65 - deps/SoftFloat-3e/source/s_subM.c | 70 - deps/SoftFloat-3e/source/s_subMagsExtF80.c | 158 - deps/SoftFloat-3e/source/s_subMagsF128.c | 139 - deps/SoftFloat-3e/source/s_subMagsF16.c | 187 - deps/SoftFloat-3e/source/s_subMagsF32.c | 143 - deps/SoftFloat-3e/source/s_subMagsF64.c | 141 - .../source/s_tryPropagateNaNExtF80M.c | 64 - .../source/s_tryPropagateNaNF128M.c | 55 - deps/SoftFloat-3e/source/softfloat_state.c | 52 - deps/SoftFloat-3e/source/ui32_to_extF80.c | 59 - deps/SoftFloat-3e/source/ui32_to_extF80M.c | 74 - deps/SoftFloat-3e/source/ui32_to_f128.c | 60 - deps/SoftFloat-3e/source/ui32_to_f128M.c | 76 - deps/SoftFloat-3e/source/ui32_to_f16.c | 65 - deps/SoftFloat-3e/source/ui32_to_f32.c | 57 - deps/SoftFloat-3e/source/ui32_to_f64.c | 59 - deps/SoftFloat-3e/source/ui64_to_extF80.c | 59 - deps/SoftFloat-3e/source/ui64_to_extF80M.c | 74 - deps/SoftFloat-3e/source/ui64_to_f128.c | 68 - deps/SoftFloat-3e/source/ui64_to_f128M.c | 86 - deps/SoftFloat-3e/source/ui64_to_f16.c | 64 - deps/SoftFloat-3e/source/ui64_to_f32.c | 64 - deps/SoftFloat-3e/source/ui64_to_f64.c | 59 - src/Compilation.zig | 194 - src/stage1.zig | 479 - src/stage1/all_types.hpp | 4746 --- src/stage1/analyze.cpp | 10443 ------ src/stage1/analyze.hpp | 314 - src/stage1/astgen.cpp | 8339 ----- src/stage1/astgen.hpp | 37 - src/stage1/bigfloat.cpp | 220 - src/stage1/bigfloat.hpp | 60 - src/stage1/bigint.cpp | 1895 -- src/stage1/bigint.hpp | 112 - src/stage1/buffer.cpp | 79 - src/stage1/buffer.hpp | 211 - src/stage1/codegen.cpp | 11034 ------- src/stage1/codegen.hpp | 40 - src/stage1/config.h.in | 30 - src/stage1/empty.cpp | 0 src/stage1/errmsg.cpp | 135 - src/stage1/errmsg.hpp | 30 - src/stage1/error.cpp | 95 - src/stage1/error.hpp | 17 - src/stage1/hash_map.hpp | 446 - src/stage1/heap.cpp | 314 - src/stage1/heap.hpp | 81 - src/stage1/ir.cpp | 26627 ---------------- src/stage1/ir.hpp | 34 - src/stage1/ir_print.cpp | 3543 -- src/stage1/ir_print.hpp | 25 - src/stage1/list.hpp | 96 - src/stage1/mem.cpp | 23 - src/stage1/mem.hpp | 139 - src/stage1/mem_hash_map.hpp | 244 - src/stage1/mem_list.hpp | 104 - src/stage1/mem_type_info.hpp | 25 - src/stage1/os.cpp | 1282 - src/stage1/os.hpp | 120 - src/stage1/parse_f128.c | 1085 - src/stage1/parse_f128.h | 21 - src/stage1/parser.cpp | 3603 --- src/stage1/parser.hpp | 29 - src/stage1/range_set.cpp | 74 - src/stage1/range_set.hpp | 30 - src/stage1/softfloat.hpp | 77 - src/stage1/softfloat_ext.cpp | 71 - src/stage1/softfloat_ext.hpp | 16 - src/stage1/stage1.cpp | 131 - src/stage1/stage1.h | 230 - src/stage1/stage2.h | 188 - src/stage1/target.cpp | 1165 - src/stage1/target.hpp | 92 - src/stage1/tokenizer.cpp | 1626 - src/stage1/tokenizer.hpp | 161 - src/stage1/util.cpp | 115 - src/stage1/util.hpp | 247 - src/stage1/util_base.hpp | 77 - src/stage1/zig0.cpp | 578 - src/stage1/zigendian.h | 34 - 491 files changed, 124927 deletions(-) delete mode 100644 deps/SoftFloat-3e-prebuilt/platform.h delete mode 100644 deps/SoftFloat-3e/COPYING.txt delete mode 100644 deps/SoftFloat-3e/README.html delete mode 100644 deps/SoftFloat-3e/README.txt delete mode 100644 deps/SoftFloat-3e/doc/SoftFloat-history.html delete mode 100644 deps/SoftFloat-3e/doc/SoftFloat-source.html delete mode 100644 deps/SoftFloat-3e/doc/SoftFloat.html delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c delete mode 100644 deps/SoftFloat-3e/source/8086-SSE/specialize.h delete mode 100644 deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c delete mode 100644 deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c delete mode 100644 deps/SoftFloat-3e/source/8086/specialize.h delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c delete mode 100644 deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h delete mode 100644 deps/SoftFloat-3e/source/extF80M_add.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_div.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_eq.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_le.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_lt.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_mul.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_rem.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_sub.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80_add.c delete mode 100644 deps/SoftFloat-3e/source/extF80_div.c delete mode 100644 deps/SoftFloat-3e/source/extF80_eq.c delete mode 100644 deps/SoftFloat-3e/source/extF80_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/extF80_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/extF80_le.c delete mode 100644 deps/SoftFloat-3e/source/extF80_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/extF80_lt.c delete mode 100644 deps/SoftFloat-3e/source/extF80_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/extF80_mul.c delete mode 100644 deps/SoftFloat-3e/source/extF80_rem.c delete mode 100644 deps/SoftFloat-3e/source/extF80_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/extF80_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/extF80_sub.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128M_add.c delete mode 100644 deps/SoftFloat-3e/source/f128M_div.c delete mode 100644 deps/SoftFloat-3e/source/f128M_eq.c delete mode 100644 deps/SoftFloat-3e/source/f128M_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/f128M_le.c delete mode 100644 deps/SoftFloat-3e/source/f128M_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f128M_lt.c delete mode 100644 deps/SoftFloat-3e/source/f128M_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f128M_mul.c delete mode 100644 deps/SoftFloat-3e/source/f128M_mulAdd.c delete mode 100644 deps/SoftFloat-3e/source/f128M_rem.c delete mode 100644 deps/SoftFloat-3e/source/f128M_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/f128M_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/f128M_sub.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128_add.c delete mode 100644 deps/SoftFloat-3e/source/f128_div.c delete mode 100644 deps/SoftFloat-3e/source/f128_eq.c delete mode 100644 deps/SoftFloat-3e/source/f128_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/f128_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/f128_le.c delete mode 100644 deps/SoftFloat-3e/source/f128_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f128_lt.c delete mode 100644 deps/SoftFloat-3e/source/f128_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f128_mul.c delete mode 100644 deps/SoftFloat-3e/source/f128_mulAdd.c delete mode 100644 deps/SoftFloat-3e/source/f128_rem.c delete mode 100644 deps/SoftFloat-3e/source/f128_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/f128_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/f128_sub.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f16_add.c delete mode 100644 deps/SoftFloat-3e/source/f16_div.c delete mode 100644 deps/SoftFloat-3e/source/f16_eq.c delete mode 100644 deps/SoftFloat-3e/source/f16_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/f16_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/f16_le.c delete mode 100644 deps/SoftFloat-3e/source/f16_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f16_lt.c delete mode 100644 deps/SoftFloat-3e/source/f16_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f16_mul.c delete mode 100644 deps/SoftFloat-3e/source/f16_mulAdd.c delete mode 100644 deps/SoftFloat-3e/source/f16_rem.c delete mode 100644 deps/SoftFloat-3e/source/f16_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/f16_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/f16_sub.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f32_add.c delete mode 100644 deps/SoftFloat-3e/source/f32_div.c delete mode 100644 deps/SoftFloat-3e/source/f32_eq.c delete mode 100644 deps/SoftFloat-3e/source/f32_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/f32_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/f32_le.c delete mode 100644 deps/SoftFloat-3e/source/f32_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f32_lt.c delete mode 100644 deps/SoftFloat-3e/source/f32_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f32_mul.c delete mode 100644 deps/SoftFloat-3e/source/f32_mulAdd.c delete mode 100644 deps/SoftFloat-3e/source/f32_rem.c delete mode 100644 deps/SoftFloat-3e/source/f32_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/f32_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/f32_sub.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f64_add.c delete mode 100644 deps/SoftFloat-3e/source/f64_div.c delete mode 100644 deps/SoftFloat-3e/source/f64_eq.c delete mode 100644 deps/SoftFloat-3e/source/f64_eq_signaling.c delete mode 100644 deps/SoftFloat-3e/source/f64_isSignalingNaN.c delete mode 100644 deps/SoftFloat-3e/source/f64_le.c delete mode 100644 deps/SoftFloat-3e/source/f64_le_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f64_lt.c delete mode 100644 deps/SoftFloat-3e/source/f64_lt_quiet.c delete mode 100644 deps/SoftFloat-3e/source/f64_mul.c delete mode 100644 deps/SoftFloat-3e/source/f64_mulAdd.c delete mode 100644 deps/SoftFloat-3e/source/f64_rem.c delete mode 100644 deps/SoftFloat-3e/source/f64_roundToInt.c delete mode 100644 deps/SoftFloat-3e/source/f64_sqrt.c delete mode 100644 deps/SoftFloat-3e/source/f64_sub.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_i32.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_i64.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_ui32.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_ui64.c delete mode 100644 deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/i32_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/i64_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/include/internals.h delete mode 100644 deps/SoftFloat-3e/source/include/opts-GCC.h delete mode 100644 deps/SoftFloat-3e/source/include/primitiveTypes.h delete mode 100644 deps/SoftFloat-3e/source/include/primitives.h delete mode 100644 deps/SoftFloat-3e/source/include/softfloat.h delete mode 100644 deps/SoftFloat-3e/source/include/softfloat_types.h delete mode 100644 deps/SoftFloat-3e/source/s_add128.c delete mode 100644 deps/SoftFloat-3e/source/s_add256M.c delete mode 100644 deps/SoftFloat-3e/source/s_addCarryM.c delete mode 100644 deps/SoftFloat-3e/source/s_addComplCarryM.c delete mode 100644 deps/SoftFloat-3e/source/s_addExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_addF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_addM.c delete mode 100644 deps/SoftFloat-3e/source/s_addMagsExtF80.c delete mode 100644 deps/SoftFloat-3e/source/s_addMagsF128.c delete mode 100644 deps/SoftFloat-3e/source/s_addMagsF16.c delete mode 100644 deps/SoftFloat-3e/source/s_addMagsF32.c delete mode 100644 deps/SoftFloat-3e/source/s_addMagsF64.c delete mode 100644 deps/SoftFloat-3e/source/s_approxRecip32_1.c delete mode 100644 deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c delete mode 100644 deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c delete mode 100644 deps/SoftFloat-3e/source/s_approxRecip_1Ks.c delete mode 100644 deps/SoftFloat-3e/source/s_compare128M.c delete mode 100644 deps/SoftFloat-3e/source/s_compare96M.c delete mode 100644 deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_countLeadingZeros16.c delete mode 100644 deps/SoftFloat-3e/source/s_countLeadingZeros32.c delete mode 100644 deps/SoftFloat-3e/source/s_countLeadingZeros64.c delete mode 100644 deps/SoftFloat-3e/source/s_countLeadingZeros8.c delete mode 100644 deps/SoftFloat-3e/source/s_eq128.c delete mode 100644 deps/SoftFloat-3e/source/s_invalidExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_invalidF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_isNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_le128.c delete mode 100644 deps/SoftFloat-3e/source/s_lt128.c delete mode 100644 deps/SoftFloat-3e/source/s_mul128By32.c delete mode 100644 deps/SoftFloat-3e/source/s_mul128MTo256M.c delete mode 100644 deps/SoftFloat-3e/source/s_mul128To256M.c delete mode 100644 deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c delete mode 100644 deps/SoftFloat-3e/source/s_mul64To128.c delete mode 100644 deps/SoftFloat-3e/source/s_mul64To128M.c delete mode 100644 deps/SoftFloat-3e/source/s_mulAddF128.c delete mode 100644 deps/SoftFloat-3e/source/s_mulAddF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_mulAddF16.c delete mode 100644 deps/SoftFloat-3e/source/s_mulAddF32.c delete mode 100644 deps/SoftFloat-3e/source/s_mulAddF64.c delete mode 100644 deps/SoftFloat-3e/source/s_negXM.c delete mode 100644 deps/SoftFloat-3e/source/s_normExtF80SigM.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackToF128.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackToF16.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackToF32.c delete mode 100644 deps/SoftFloat-3e/source/s_normRoundPackToF64.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalExtF80Sig.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalF128Sig.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c delete mode 100644 deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c delete mode 100644 deps/SoftFloat-3e/source/s_remStepMBy32.c delete mode 100644 deps/SoftFloat-3e/source/s_roundMToI64.c delete mode 100644 deps/SoftFloat-3e/source/s_roundMToUI64.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackMToF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackToExtF80.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackToF128.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackToF16.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackToF32.c delete mode 100644 deps/SoftFloat-3e/source/s_roundPackToF64.c delete mode 100644 deps/SoftFloat-3e/source/s_roundToI32.c delete mode 100644 deps/SoftFloat-3e/source/s_roundToI64.c delete mode 100644 deps/SoftFloat-3e/source/s_roundToUI32.c delete mode 100644 deps/SoftFloat-3e/source/s_roundToUI64.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftLeftM.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftNormSigF128M.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam128.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam256M.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam32.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam64.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightJamM.c delete mode 100644 deps/SoftFloat-3e/source/s_shiftRightM.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftLeft128.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftLeftM.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRight128.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightJam128.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightJam64.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightJam64Extra.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightJamM.c delete mode 100644 deps/SoftFloat-3e/source/s_shortShiftRightM.c delete mode 100644 deps/SoftFloat-3e/source/s_sub128.c delete mode 100644 deps/SoftFloat-3e/source/s_sub1XM.c delete mode 100644 deps/SoftFloat-3e/source/s_sub256M.c delete mode 100644 deps/SoftFloat-3e/source/s_subM.c delete mode 100644 deps/SoftFloat-3e/source/s_subMagsExtF80.c delete mode 100644 deps/SoftFloat-3e/source/s_subMagsF128.c delete mode 100644 deps/SoftFloat-3e/source/s_subMagsF16.c delete mode 100644 deps/SoftFloat-3e/source/s_subMagsF32.c delete mode 100644 deps/SoftFloat-3e/source/s_subMagsF64.c delete mode 100644 deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c delete mode 100644 deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c delete mode 100644 deps/SoftFloat-3e/source/softfloat_state.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/ui32_to_f64.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_extF80.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_extF80M.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_f128.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_f128M.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_f16.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_f32.c delete mode 100644 deps/SoftFloat-3e/source/ui64_to_f64.c delete mode 100644 src/stage1.zig delete mode 100644 src/stage1/all_types.hpp delete mode 100644 src/stage1/analyze.cpp delete mode 100644 src/stage1/analyze.hpp delete mode 100644 src/stage1/astgen.cpp delete mode 100644 src/stage1/astgen.hpp delete mode 100644 src/stage1/bigfloat.cpp delete mode 100644 src/stage1/bigfloat.hpp delete mode 100644 src/stage1/bigint.cpp delete mode 100644 src/stage1/bigint.hpp delete mode 100644 src/stage1/buffer.cpp delete mode 100644 src/stage1/buffer.hpp delete mode 100644 src/stage1/codegen.cpp delete mode 100644 src/stage1/codegen.hpp delete mode 100644 src/stage1/config.h.in delete mode 100644 src/stage1/empty.cpp delete mode 100644 src/stage1/errmsg.cpp delete mode 100644 src/stage1/errmsg.hpp delete mode 100644 src/stage1/error.cpp delete mode 100644 src/stage1/error.hpp delete mode 100644 src/stage1/hash_map.hpp delete mode 100644 src/stage1/heap.cpp delete mode 100644 src/stage1/heap.hpp delete mode 100644 src/stage1/ir.cpp delete mode 100644 src/stage1/ir.hpp delete mode 100644 src/stage1/ir_print.cpp delete mode 100644 src/stage1/ir_print.hpp delete mode 100644 src/stage1/list.hpp delete mode 100644 src/stage1/mem.cpp delete mode 100644 src/stage1/mem.hpp delete mode 100644 src/stage1/mem_hash_map.hpp delete mode 100644 src/stage1/mem_list.hpp delete mode 100644 src/stage1/mem_type_info.hpp delete mode 100644 src/stage1/os.cpp delete mode 100644 src/stage1/os.hpp delete mode 100644 src/stage1/parse_f128.c delete mode 100644 src/stage1/parse_f128.h delete mode 100644 src/stage1/parser.cpp delete mode 100644 src/stage1/parser.hpp delete mode 100644 src/stage1/range_set.cpp delete mode 100644 src/stage1/range_set.hpp delete mode 100644 src/stage1/softfloat.hpp delete mode 100644 src/stage1/softfloat_ext.cpp delete mode 100644 src/stage1/softfloat_ext.hpp delete mode 100644 src/stage1/stage1.cpp delete mode 100644 src/stage1/stage1.h delete mode 100644 src/stage1/stage2.h delete mode 100644 src/stage1/target.cpp delete mode 100644 src/stage1/target.hpp delete mode 100644 src/stage1/tokenizer.cpp delete mode 100644 src/stage1/tokenizer.hpp delete mode 100644 src/stage1/util.cpp delete mode 100644 src/stage1/util.hpp delete mode 100644 src/stage1/util_base.hpp delete mode 100644 src/stage1/zig0.cpp delete mode 100644 src/stage1/zigendian.h diff --git a/deps/SoftFloat-3e-prebuilt/platform.h b/deps/SoftFloat-3e-prebuilt/platform.h deleted file mode 100644 index 2c4a0ec88ec3..000000000000 --- a/deps/SoftFloat-3e-prebuilt/platform.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef ZIG_DEP_SOFTFLOAT_PLATFORM_H -#define ZIG_DEP_SOFTFLOAT_PLATFORM_H - -#if defined(__BIG_ENDIAN__) -#define BIGENDIAN 1 -#elif defined(_BIG_ENDIAN) && (_BIG_ENDIAN == 1) -#define BIGENDIAN 1 -#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define BIGENDIAN 1 -#elif defined(__ARMEB__) -#define BIGENDIAN 1 -#elif defined(__THUMBEB__) -#define BIGENDIAN 1 -#elif defined(__AARCH64EB__) -#define BIGENDIAN 1 -#elif defined(_MIPSEB) -#define BIGENDIAN 1 -#elif defined(__MIPSEB) -#define BIGENDIAN 1 -#elif defined(__MIPSEB__) -#define BIGENDIAN 1 -#elif defined(__sparc) -#define BIGENDIAN 1 -#elif defined(__sparc__) -#define BIGENDIAN 1 -#elif defined(_POWER) -#define BIGENDIAN 1 -#elif defined(__hpux) -#define BIGENDIAN 1 -#elif defined(__hppa) -#define BIGENDIAN 1 -#elif defined(_POWER) -#define BIGENDIAN 1 -#elif defined(__s390__) -#define BIGENDIAN 1 -#endif - -#if defined(__LITTLE_ENDIAN__) -#define LITTLEENDIAN 1 -#elif defined(_LITTLE_ENDIAN) && (_LITTLE_ENDIAN == 1) -#define LITTLEENDIAN 1 -#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define LITTLEENDIAN 1 -#elif defined(__ARMEL__) -#define LITTLEENDIAN 1 -#elif defined(__THUMBEL__) -#define LITTLEENDIAN 1 -#elif defined(__AARCH64EL__) -#define LITTLEENDIAN 1 -#elif defined(_MIPSEL) -#define LITTLEENDIAN 1 -#elif defined(__MIPSEL) -#define LITTLEENDIAN 1 -#elif defined(__MIPSEL__) -#define LITTLEENDIAN 1 -#elif defined(__i386__) -#define LITTLEENDIAN 1 -#elif defined(__alpha__) -#define LITTLEENDIAN 1 -#elif defined(__ia64) -#define LITTLEENDIAN 1 -#elif defined(__ia64__) -#define LITTLEENDIAN 1 -#elif defined(_M_IX86) -#define LITTLEENDIAN 1 -#elif defined(_M_IA64) -#define LITTLEENDIAN 1 -#elif defined(_M_ALPHA) -#define LITTLEENDIAN 1 -#elif defined(__amd64) -#define LITTLEENDIAN 1 -#elif defined(__amd64__) -#define LITTLEENDIAN 1 -#elif defined(_M_AMD64) -#define LITTLEENDIAN 1 -#elif defined(__x86_64) -#define LITTLEENDIAN 1 -#elif defined(__x86_64__) -#define LITTLEENDIAN 1 -#elif defined(_M_X64) -#define LITTLEENDIAN 1 -#elif defined(__bfin__) -#define LITTLEENDIAN 1 -#endif - -#if defined(LITTLEENDIAN) && defined(BIGENDIAN) -#error unable to detect endianness -#elif !defined(LITTLEENDIAN) && !defined(BIGENDIAN) -#error unable to detect endianness -#endif - -#define INLINE inline -#if _MSC_VER -#define THREAD_LOCAL __declspec(thread) -#else -#define THREAD_LOCAL __thread -#endif - -#endif diff --git a/deps/SoftFloat-3e/COPYING.txt b/deps/SoftFloat-3e/COPYING.txt deleted file mode 100644 index b5690face082..000000000000 --- a/deps/SoftFloat-3e/COPYING.txt +++ /dev/null @@ -1,37 +0,0 @@ - -License for Berkeley SoftFloat Release 3e - -John R. Hauser -2018 January 20 - -The following applies to the whole of SoftFloat Release 3e as well as to -each source file individually. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions, and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/deps/SoftFloat-3e/README.html b/deps/SoftFloat-3e/README.html deleted file mode 100644 index 7989e0c2602e..000000000000 --- a/deps/SoftFloat-3e/README.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - -Berkeley SoftFloat Package Overview - - - - -

Package Overview for Berkeley SoftFloat Release 3e

- -

-John R. Hauser
-2018 January 20
-

- -

-Berkeley SoftFloat is a software implementation of binary floating-point that -conforms to the IEEE Standard for Floating-Point Arithmetic. -SoftFloat is distributed in the form of C source code. -Building the SoftFloat sources generates a library file (typically -softfloat.a or libsoftfloat.a) containing the -floating-point subroutines. -

- -

-The SoftFloat package is documented in the following files in the -doc subdirectory: -

- - - - - - - - - - - - - -
SoftFloat.htmlDocumentation for using the SoftFloat functions.
SoftFloat-source.htmlDocumentation for building SoftFloat.
SoftFloat-history.html   History of the major changes to SoftFloat.
-
-Other files in the package comprise the source code for SoftFloat. -

- - - diff --git a/deps/SoftFloat-3e/README.txt b/deps/SoftFloat-3e/README.txt deleted file mode 100644 index 1613c7671800..000000000000 --- a/deps/SoftFloat-3e/README.txt +++ /dev/null @@ -1,21 +0,0 @@ - -Package Overview for Berkeley SoftFloat Release 3e - -John R. Hauser -2018 January 20 - -Berkeley SoftFloat is a software implementation of binary floating-point -that conforms to the IEEE Standard for Floating-Point Arithmetic. SoftFloat -is distributed in the form of C source code. Building the SoftFloat sources -generates a library file (typically "softfloat.a" or "libsoftfloat.a") -containing the floating-point subroutines. - -The SoftFloat package is documented in the following files in the "doc" -subdirectory: - - SoftFloat.html Documentation for using the SoftFloat functions. - SoftFloat-source.html Documentation for building SoftFloat. - SoftFloat-history.html History of the major changes to SoftFloat. - -Other files in the package comprise the source code for SoftFloat. - diff --git a/deps/SoftFloat-3e/doc/SoftFloat-history.html b/deps/SoftFloat-3e/doc/SoftFloat-history.html deleted file mode 100644 index daa48ca3b374..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat-history.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - -Berkeley SoftFloat History - - - - -

History of Berkeley SoftFloat, to Release 3e

- -

-John R. Hauser
-2018 January 20
-

- - -

Release 3e (2018 January)

- -
    - -
  • -Changed the default numeric code for optional rounding mode odd -(round to odd, also known as jamming) from 5 to 6. - -
  • -Modified the behavior of rounding mode odd when rounding to an -integer value (either conversion to an integer format or a -‘roundToInt’ function). -Previously, for those cases only, rounding mode odd acted the same -as rounding to minimum magnitude. -Now all operations are rounded consistently. - -
  • -Fixed some errors in the specialization code modeling Intel x86 floating-point, -specifically the integers returned on invalid operations and the propagation of -NaN payloads in a few rare cases. - -
  • -Added specialization code modeling ARM floating-point, conforming to VFPv2 or -later. - -
  • -Added an example target for ARM processors. - -
  • -Fixed a minor bug whereby function f16_to_ui64 might return a -different integer than expected in the case that the floating-point operand is -negative. - -
  • -Added example target-specific optimization for GCC, employing GCC instrinsics -and support for 128-bit integer arithmetic. - -
  • -Made other minor improvements. - -
- - -

Release 3d (2017 August)

- -
    - -
  • -Fixed bugs in the square root functions for 64-bit -double-precision, 80-bit double-extended-precision, and -128-bit quadruple-precision. -For 64-bit double-precision (f64_sqrt), the result -could sometimes be off by 1 unit in the last place -(1 ulp) from what it should be. -For the larger formats, the square root could be wrong in a large portion of -the less-significant bits. -(A bug in f128_sqrt was first reported by Alexei Sibidanov.) - -
- - -

Release 3c (2017 February)

- -
    - -
  • -Added optional rounding mode odd (round to odd, also known as -jamming). - -
  • -Corrected the documentation concerning non-canonical representations in -80-bit double-extended-precision. - -
- - -

Release 3b (2016 July)

- -
    - -
  • -Implemented the common 16-bit “half-precision” -floating-point format (float16_t). - -
  • -Made the integer values returned on invalid conversions to integer formats -be determined by the port-specific specialization instead of being the same for -all ports. - -
  • -Added preprocessor macro THREAD_LOCAL to allow the floating-point -state (modes and exception flags) to be made per-thread. - -
  • -Modified the provided Makefiles to allow some options to be overridden from the -make command. - -
  • -Made other minor improvements. - -
- - -

Release 3a (2015 October)

- -
    - -
  • -Replaced the license text supplied by the University of California, Berkeley. - -
- - -

Release 3 (2015 February)

- -
    - -
  • -Complete rewrite, funded by the University of California, Berkeley, and -consequently having a different use license than earlier releases. -Major changes included renaming most types and functions, upgrading some -algorithms, restructuring the source files, and making SoftFloat into a true -library. - -
  • -Added functions to convert between floating-point and unsigned integers, both -32-bit and 64-bit (uint32_t and -uint64_t). - -
  • -Added functions for fused multiply-add, for all supported floating-point -formats except 80-bit double-extended-precision. - -
  • -Added support for a fifth rounding mode, near_maxMag (round to -nearest, with ties to maximum magnitude, away from zero). - -
  • -Dropped the timesoftfloat program (now part of the Berkeley -TestFloat package). - -
- - -

Release 2c (2015 January)

- -
    - -
  • -Fixed mistakes affecting some 64-bit processors. - -
  • -Further improved the documentation and the wording for the legal restrictions -on using SoftFloat releases through 2c (not applicable to -Release 3 or later). - -
- - -

Release 2b (2002 May)

- -
    - -
  • -Made minor updates to the documentation, including improved wording for the -legal restrictions on using SoftFloat. - -
- - -

Release 2a (1998 December)

- -
    - -
  • -Added functions to convert between 64-bit integers -(int64) and all supported floating-point formats. - -
  • -Fixed a bug in all 64-bit-version square root functions except -float32_sqrt that caused the result sometimes to be off by -1 unit in the last place (1 ulp) from what it should -be. -(Bug discovered by Paul Donahue.) - -
  • -Improved the Makefiles. -
- - -

Release 2 (1997 June)

- -
    - -
  • -Created the 64-bit (bits64) version, adding the -floatx80 and float128 formats. - -
  • -Changed the source directory structure, splitting the sources into a -bits32 and a bits64 version. -Renamed environment.h to milieu.h to avoid confusion -with environment variables. - -
  • -Fixed a small error that caused float64_round_to_int often to -round the wrong way in nearest/even mode when the operand was between -220 and 221 and halfway between two integers. - -
- - -

Release 1a (1996 July)

- -
    - -
  • -Corrected a mistake that caused borderline underflow cases not to raise the -underflow flag when they should have. -(Problem reported by Doug Priest.) - -
  • -Added the float_detect_tininess variable to control whether -tininess is detected before or after rounding. - -
- - -

Release 1 (1996 July)

- -
    - -
  • -Original release, based on work done for the International Computer Science -Institute (ICSI) in Berkeley, California. - -
- - - - diff --git a/deps/SoftFloat-3e/doc/SoftFloat-source.html b/deps/SoftFloat-3e/doc/SoftFloat-source.html deleted file mode 100644 index d4b85f7b092f..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat-source.html +++ /dev/null @@ -1,686 +0,0 @@ - - - - -Berkeley SoftFloat Source Documentation - - - - -

Berkeley SoftFloat Release 3e: Source Documentation

- -

-John R. Hauser
-2018 January 20
-

- - -

Contents

- -
- --- - - - - - - - - - - - - - - - - - - - -
1. Introduction
2. Limitations
3. Acknowledgments and License
4. SoftFloat Package Directory Structure
5. Issues for Porting SoftFloat to a New Target
5.1. Standard Headers <stdbool.h> and - <stdint.h>
5.2. Specializing Floating-Point Behavior
5.3. Macros for Build Options
5.4. Adapting a Template Target Directory
5.5. Target-Specific Optimization of Primitive Functions
6. Testing SoftFloat
7. Providing SoftFloat as a Common Library for Applications
8. Contact Information
-
- - -

1. Introduction

- -

-This document gives information needed for compiling and/or porting Berkeley -SoftFloat, a library of C functions implementing binary floating-point -conforming to the IEEE Standard for Floating-Point Arithmetic. -For basic documentation about SoftFloat refer to -SoftFloat.html. -

- -

-The source code for SoftFloat is intended to be relatively machine-independent -and should be compilable with any ISO-Standard C compiler that also supports -64-bit integers. -SoftFloat has been successfully compiled with the GNU C Compiler -(gcc) for several platforms. -

- -

-Release 3 of SoftFloat was a complete rewrite relative to -Release 2 or earlier. -Changes to the interface of SoftFloat functions are documented in -SoftFloat.html. -The current version of SoftFloat is Release 3e. -

- - -

2. Limitations

- -

-SoftFloat assumes the computer has an addressable byte size of either 8 or -16 bits. -(Nearly all computers in use today have 8-bit bytes.) -

- -

-SoftFloat is written in C and is designed to work with other C code. -The C compiler used must conform at a minimum to the 1989 ANSI standard for the -C language (same as the 1990 ISO standard) and must in addition support basic -arithmetic on 64-bit integers. -Earlier releases of SoftFloat included implementations of 32-bit -single-precision and 64-bit double-precision floating-point that -did not require 64-bit integers, but this option is not supported -starting with Release 3. -Since 1999, ISO standards for C have mandated compiler support for -64-bit integers. -A compiler conforming to the 1999 C Standard or later is recommended but not -strictly required. -

- -

-C Standard header files <stdbool.h> and -<stdint.h> are required for defining standard Boolean and -integer types. -If these headers are not supplied with the C compiler, minimal substitutes must -be provided. -SoftFloat’s dependence on these headers is detailed later in -section 5.1, Standard Headers <stdbool.h> -and <stdint.h>. -

- - -

3. Acknowledgments and License

- -

-The SoftFloat package was written by me, John R. Hauser. -Release 3 of SoftFloat was a completely new implementation -supplanting earlier releases. -The project to create Release 3 (now through 3e) was -done in the employ of the University of California, Berkeley, within the -Department of Electrical Engineering and Computer Sciences, first for the -Parallel Computing Laboratory (Par Lab) and then for the ASPIRE Lab. -The work was officially overseen by Prof. Krste Asanovic, with funding provided -by these sources: -

- ---- - - - - - - - - - -
Par Lab: -Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery -(Award #DIG07-10227), with additional support from Par Lab affiliates Nokia, -NVIDIA, Oracle, and Samsung. -
ASPIRE Lab: -DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from -ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA, -Oracle, and Samsung. -
-
-

- -

-The following applies to the whole of SoftFloat Release 3e as well -as to each source file individually. -

- -

-Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. -All rights reserved. -

- -

-Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -

    - -
  1. -

    -Redistributions of source code must retain the above copyright notice, this -list of conditions, and the following disclaimer. -

    - -
  2. -

    -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions, and the following disclaimer in the documentation and/or -other materials provided with the distribution. -

    - -
  3. -

    -Neither the name of the University nor the names of its contributors may be -used to endorse or promote products derived from this software without specific -prior written permission. -

    - -
-

- -

-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS”, -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. -IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -

- - -

4. SoftFloat Package Directory Structure

- -

-Because SoftFloat is targeted to multiple platforms, its source code is -slightly scattered between target-specific and target-independent directories -and files. -The supplied directory structure is as follows: -

-
-doc
-source
-    include
-    8086
-    8086-SSE
-    ARM-VFPv2
-    ARM-VFPv2-defaultNaN
-build
-    template-FAST_INT64
-    template-not-FAST_INT64
-    Linux-386-GCC
-    Linux-386-SSE2-GCC
-    Linux-x86_64-GCC
-    Linux-ARM-VFPv2-GCC
-    Win32-MinGW
-    Win32-SSE2-MinGW
-    Win64-MinGW-w64
-
-
-The majority of the SoftFloat sources are provided in the source -directory. -The include subdirectory contains several header files -(unsurprisingly), while the other subdirectories of source contain -source files that specialize the floating-point behavior to match particular -processor families: -
-
-
8086
-
-Intel’s older, 8087-derived floating-point, extended to all supported -floating-point types -
-
8086-SSE
-
-Intel’s x86 processors with Streaming SIMD Extensions (SSE) and later -compatible extensions, having 8087 behavior for 80-bit -double-extended-precision (extFloat80_t) and SSE behavior for -other floating-point types -
-
ARM-VFPv2
-
-ARM’s VFPv2 or later floating-point, with NaN payload propagation -
-
ARM-VFPv2-defaultNaN
-
-ARM’s VFPv2 or later floating-point, with the “default NaN” -option -
-
-
-If other specializations are attempted, these would be expected to be other -subdirectories of source alongside the ones listed above. -Specialization is covered later, in section 5.2, Specializing -Floating-Point Behavior. -

- -

-The build directory is intended to contain a subdirectory for each -target platform for which a build of the SoftFloat library may be created. -For each build target, the target’s subdirectory is where all derived -object files and the completed SoftFloat library (typically -softfloat.a or libsoftfloat.a) are created. -The two template subdirectories are not actual build targets but -contain sample files for creating new target directories. -(The meaning of FAST_INT64 will be explained later.) -

- -

-Ignoring the template directories, the supplied target directories -are intended to follow a naming system of -<execution-environment>-<compiler>. -For the example targets, -<execution-environment> is -Linux-386, Linux-386-SSE2, -Linux-x86_64, -Linux-ARM-VFPv2, Win32, -Win32-SSE2, or Win64, and -<compiler> is GCC, -MinGW, or MinGW-w64. -

- -

-All of the supplied target directories are merely examples that may or may not -be correct for compiling on any particular system. -Despite requests, there are currently no plans to include and maintain in the -SoftFloat package the build files needed for a great many users’ -compilation environments, which can span a huge range of operating systems, -compilers, and other tools. -

- -

-As supplied, each target directory contains two files: -

-
-Makefile
-platform.h
-
-
-The provided Makefile is written for GNU make. -A build of SoftFloat for the specific target is begun by executing the -make command with the target directory as the current directory. -A completely different build tool can be used if an appropriate -Makefile equivalent is created. -

- -

-The platform.h header file exists to provide a location for -additional C declarations specific to the build target. -Every C source file of SoftFloat contains a #include for -platform.h. -In many cases, the contents of platform.h can be as simple as one -or two lines of code. -At the other extreme, to get maximal performance from SoftFloat, it may be -desirable to include in header platform.h (directly or via -#include) declarations for numerous target-specific optimizations. -Such possibilities are discussed in the next section, Issues for Porting -SoftFloat to a New Target. -If the target’s compiler or library has bugs or other shortcomings, -workarounds for these issues may also be possible with target-specific -declarations in platform.h, avoiding the need to modify the main -SoftFloat sources. -

- - -

5. Issues for Porting SoftFloat to a New Target

- -

5.1. Standard Headers <stdbool.h> and <stdint.h>

- -

-The SoftFloat sources make use of standard headers -<stdbool.h> and <stdint.h>, which have -been part of the ISO C Standard Library since 1999. -With any recent compiler, these standard headers are likely to be supported, -even if the compiler does not claim complete conformance to the latest ISO C -Standard. -For older or nonstandard compilers, substitutes for -<stdbool.h> and <stdint.h> may need to be -created. -SoftFloat depends on these names from <stdbool.h>: -

-
-bool
-true
-false
-
-
-and on these names from <stdint.h>: -
-
-uint16_t
-uint32_t
-uint64_t
-int32_t
-int64_t
-UINT64_C
-INT64_C
-uint_least8_t
-uint_fast8_t
-uint_fast16_t
-uint_fast32_t
-uint_fast64_t
-int_fast8_t
-int_fast16_t
-int_fast32_t
-int_fast64_t
-
-
-

- - -

5.2. Specializing Floating-Point Behavior

- -

-The IEEE Floating-Point Standard allows for some flexibility in a conforming -implementation, particularly concerning NaNs. -The SoftFloat source directory is supplied with some -specialization subdirectories containing possible definitions for this -implementation-specific behavior. -For example, the 8086 and 8086-SSE -subdirectories have source files that specialize SoftFloat’s behavior to -match that of Intel’s x86 line of processors. -The files in a specialization subdirectory must determine: -

    -
  • -whether tininess for underflow is detected before or after rounding by default; -
  • -how signaling NaNs are distinguished from quiet NaNs; -
  • -what (if anything) special happens when exceptions are raised; -
  • -the default generated quiet NaNs; -
  • -how NaNs are propagated from function inputs to output; and -
  • -the integer results returned when conversions to integer type raise the -invalid exception. -
-

- -

-As provided, the build process for a target expects to involve exactly -one specialization directory that defines all of these -implementation-specific details for the target. -A specialization directory such as 8086 is expected to contain a -header file called specialize.h, together with whatever other -source files are needed to complete the specialization. -

- -

-A new build target may use an existing specialization, such as the ones -provided by the 8086 and 8086-SSE -subdirectories. -If a build target needs a new specialization, different from any existing ones, -it is recommended that a new specialization directory be created for this -purpose. -The specialize.h header file from any of the provided -specialization subdirectories can be used as a model for what definitions are -needed. -

- - -

5.3. Macros for Build Options

- -

-The SoftFloat source files adapt the floating-point implementation according to -several C preprocessor macros: -

-
-
LITTLEENDIAN -
-Must be defined for little-endian machines; must not be defined for big-endian -machines. -
INLINE -
-Specifies the sequence of tokens used to indicate that a C function should be -inlined. -If macro INLINE_LEVEL is defined with a value of 1 or higher, this -macro must be defined; otherwise, this macro is ignored and need not be -defined. -For compilers that conform to the C Standard’s rules for inline -functions, this macro can be defined as the single keyword inline. -For other compilers that follow a convention pre-dating the standardization of -inline, this macro may need to be defined to extern -inline. -
THREAD_LOCAL -
-Can be defined to a sequence of tokens that, when appearing at the start of a -variable declaration, indicates to the C compiler that the variable is -per-thread, meaning that each execution thread gets its own separate -instance of the variable. -This macro is used in header softfloat.h in the declarations of -variables softfloat_roundingMode, -softfloat_detectTininess, extF80_roundingPrecision, -and softfloat_exceptionFlags. -If macro THREAD_LOCAL is left undefined, these variables will -default to being ordinary global variables. -Depending on the compiler, possible valid definitions of this macro include -_Thread_local and __thread. -
-
-
SOFTFLOAT_ROUND_ODD -
-Can be defined to enable support for optional rounding mode -softfloat_round_odd. -
-
-
INLINE_LEVEL -
-Can be defined to an integer to determine the degree of inlining requested of -the compiler. -Larger numbers request that more inlining be done. -If this macro is not defined or is defined to a value less than 1 -(zero or negative), no inlining is requested. -The maximum effective value is no higher than 5. -Defining this macro to a value greater than 5 is the same as defining it -to 5. -
SOFTFLOAT_FAST_INT64 -
-Can be defined to indicate that the build target’s implementation of -64-bit arithmetic is efficient. -For newer 64-bit processors, this macro should usually be defined. -For very small microprocessors whose buses and registers are 8-bit -or 16-bit in size, this macro should usually not be defined. -Whether this macro should be defined for a 32-bit processor may -depend on the target machine and the applications that will use SoftFloat. -
SOFTFLOAT_FAST_DIV32TO16 -
-Can be defined to indicate that the target’s division operator -in C (written as /) is reasonably efficient for -dividing a 32-bit unsigned integer by a 16-bit -unsigned integer. -Setting this macro may affect the performance of function f16_div. -
SOFTFLOAT_FAST_DIV64TO32 -
-Can be defined to indicate that the target’s division operator -in C (written as /) is reasonably efficient for -dividing a 64-bit unsigned integer by a 32-bit -unsigned integer. -Setting this macro may affect the performance of division, remainder, and -square root operations other than f16_div. -
-
-

- -

-Following the usual custom for C, for most of these macros (all -except INLINE, THREAD_LOCAL, and -INLINE_LEVEL), the content of any definition is irrelevant; -what matters is a macro’s effect on #ifdef directives. -

- -

-It is recommended that any definitions of macros LITTLEENDIAN, -INLINE, and THREAD_LOCAL be made in a build -target’s platform.h header file, because these macros are -expected to be determined inflexibly by the target machine and compiler. -The other five macros select options and control optimization, and thus might -be better located in the target’s Makefile (or its equivalent). -

- - -

5.4. Adapting a Template Target Directory

- -

-In the build directory, two template subdirectories -provide models for new target directories. -Two different templates exist because different functions are needed in the -SoftFloat library depending on whether macro SOFTFLOAT_FAST_INT64 -is defined. -If macro SOFTFLOAT_FAST_INT64 will be defined, -template-FAST_INT64 is the template to use; -otherwise, template-not-FAST_INT64 is the appropriate -template. -A new target directory can be created by copying the correct template directory -and editing the files inside. -To avoid confusion, it would be wise to refrain from editing the files within a -template directory directly. -

- - -

5.5. Target-Specific Optimization of Primitive Functions

- -

-Header file primitives.h (in directory -source/include) declares macros and functions for numerous -underlying arithmetic operations upon which many of SoftFloat’s -floating-point functions are ultimately built. -The SoftFloat sources include implementations of all of these functions/macros, -written as standard C code, so a complete and correct SoftFloat library can be -created using only the supplied code for all functions. -However, for many targets, SoftFloat’s performance can be improved by -substituting target-specific implementations of some of the functions/macros -declared in primitives.h. -

- -

-For example, primitives.h declares a function called -softfloat_countLeadingZeros32 that takes an unsigned -32-bit integer as an argument and returns the number of the -integer’s most-significant bits that are zeros. -While the SoftFloat sources include an implementation of this function written -in standard C, many processors can perform this same function -directly in only one or two machine instructions. -An alternative, target-specific implementation that maps to those instructions -is likely to be more efficient than the generic C code from the SoftFloat -package. -

- -

-A build target can replace the supplied version of any function or macro of -primitives.h by defining a macro with the same name in the -target’s platform.h header file. -For this purpose, it may be helpful for platform.h to -#include header file primitiveTypes.h, which defines -types used for arguments and results of functions declared in -primitives.h. -When a desired replacement implementation is a function, not a macro, it is -sufficient for platform.h to include the line -

-
-#define <function-name> <function-name>
-
-
-where <function-name> is the name of the -function. -This technically defines <function-name> -as a macro, but one that resolves to the same name, which may then be a -function. -(A preprocessor that conforms to the C Standard is required to limit recursive -macro expansion from being applied more than once.) -

- -

-The supplied header file opts-GCC.h (in directory -source/include) provides an example of target-specific -optimization for the GCC compiler. -Each GCC target example in the build directory has -

-#include "opts-GCC.h" -
-in its platform.h header file. -Before opts-GCC.h is included, the following macros must be -defined (or not) to control which features are invoked: -
-
-
SOFTFLOAT_BUILTIN_CLZ
-
-If defined, SoftFloat’s internal -‘countLeadingZeros’ functions use intrinsics -__builtin_clz and __builtin_clzll. -
-
SOFTFLOAT_INTRINSIC_INT128
-
-If defined, SoftFloat makes use of GCC’s nonstandard 128-bit -integer type __int128. -
-
-
-On some machines, these improvements are observed to increase the speeds of -f64_mul and f128_mul by around 20 to 25%, although -other functions receive less dramatic boosts, or none at all. -Results can vary greatly across different platforms. -

- - -

6. Testing SoftFloat

- -

-SoftFloat can be tested using the testsoftfloat program by the -same author. -This program is part of the Berkeley TestFloat package available at the Web -page -http://www.jhauser.us/arithmetic/TestFloat.html. -The TestFloat package also has a program called timesoftfloat that -measures the speed of SoftFloat’s floating-point functions. -

- - -

7. Providing SoftFloat as a Common Library for Applications

- -

-Header file softfloat.h defines the SoftFloat interface as seen by -clients. -If the SoftFloat library will be made a common library for programs on a -system, the supplied softfloat.h has a couple of deficiencies for -this purpose: -

    -
  • -As supplied, softfloat.h depends on another header, -softfloat_types.h, that is not intended for public use but which -must also be visible to the programmer’s compiler. -
  • -More troubling, at the time softfloat.h is included in a C source -file, macros SOFTFLOAT_FAST_INT64 and THREAD_LOCAL -must be defined, or not defined, consistent with how these macro were defined -when the SoftFloat library was built. -
-In the situation that new programs may regularly #include header -file softfloat.h, it is recommended that a custom, self-contained -version of this header file be created that eliminates these issues. -

- - -

8. Contact Information

- -

-At the time of this writing, the most up-to-date information about SoftFloat -and the latest release can be found at the Web page -http://www.jhauser.us/arithmetic/SoftFloat.html. -

- - - - diff --git a/deps/SoftFloat-3e/doc/SoftFloat.html b/deps/SoftFloat-3e/doc/SoftFloat.html deleted file mode 100644 index bb41770ec521..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat.html +++ /dev/null @@ -1,1527 +0,0 @@ - - - - -Berkeley SoftFloat Library Interface - - - - -

Berkeley SoftFloat Release 3e: Library Interface

- -

-John R. Hauser
-2018 January 20
-

- - -

Contents

- -
- --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1. Introduction
2. Limitations
3. Acknowledgments and License
4. Types and Functions
4.1. Boolean and Integer Types
4.2. Floating-Point Types
4.3. Supported Floating-Point Functions
4.4. Non-canonical Representations in extFloat80_t
4.5. Conventions for Passing Arguments and Results
5. Reserved Names
6. Mode Variables
6.1. Rounding Mode
6.2. Underflow Detection
6.3. Rounding Precision for the 80-Bit Extended Format
7. Exceptions and Exception Flags
8. Function Details
8.1. Conversions from Integer to Floating-Point
8.2. Conversions from Floating-Point to Integer
8.3. Conversions Among Floating-Point Types
8.4. Basic Arithmetic Functions
8.5. Fused Multiply-Add Functions
8.6. Remainder Functions
8.7. Round-to-Integer Functions
8.8. Comparison Functions
8.9. Signaling NaN Test Functions
8.10. Raise-Exception Function
9. Changes from SoftFloat Release 2
9.1. Name Changes
9.2. Changes to Function Arguments
9.3. Added Capabilities
9.4. Better Compatibility with the C Language
9.5. New Organization as a Library
9.6. Optimization Gains (and Losses)
10. Future Directions
11. Contact Information
-
- - -

1. Introduction

- -

-Berkeley SoftFloat is a software implementation of binary floating-point that -conforms to the IEEE Standard for Floating-Point Arithmetic. -The current release supports five binary formats: 16-bit -half-precision, 32-bit single-precision, 64-bit -double-precision, 80-bit double-extended-precision, and -128-bit quadruple-precision. -The following functions are supported for each format: -

    -
  • -addition, subtraction, multiplication, division, and square root; -
  • -fused multiply-add as defined by the IEEE Standard, except for -80-bit double-extended-precision; -
  • -remainder as defined by the IEEE Standard; -
  • -round to integral value; -
  • -comparisons; -
  • -conversions to/from other supported formats; and -
  • -conversions to/from 32-bit and 64-bit integers, -signed and unsigned. -
-All operations required by the original 1985 version of the IEEE Floating-Point -Standard are implemented, except for conversions to and from decimal. -

- -

-This document gives information about the types defined and the routines -implemented by SoftFloat. -It does not attempt to define or explain the IEEE Floating-Point Standard. -Information about the standard is available elsewhere. -

- -

-The current version of SoftFloat is Release 3e. -This release modifies the behavior of the rarely used odd rounding mode -(round to odd, also known as jamming), and also adds some new -specialization and optimization examples for those compiling SoftFloat. -

- -

-The previous Release 3d fixed bugs that were found in the square -root functions for the 64-bit, 80-bit, and -128-bit floating-point formats. -(Thanks to Alexei Sibidanov at the University of Victoria for reporting an -incorrect result.) -The bugs affected all prior Release-3 versions of SoftFloat -through 3c. -The flaw in the 64-bit floating-point square root function was of -very minor impact, causing a 1-ulp error (1 unit in -the last place) a few times out of a billion. -The bugs in the 80-bit and 128-bit square root -functions were more serious. -Although incorrect results again occurred only a few times out of a billion, -when they did occur a large portion of the less-significant bits could be -wrong. -

- -

-Among earlier releases, 3b was notable for adding support for the -16-bit half-precision format. -For more about the evolution of SoftFloat releases, see -SoftFloat-history.html. -

- -

-The functional interface of SoftFloat Release 3 and later differs -in many details from the releases that came before. -For specifics of these differences, see section 9 below, -Changes from SoftFloat Release 2. -

- - -

2. Limitations

- -

-SoftFloat assumes the computer has an addressable byte size of 8 or -16 bits. -(Nearly all computers in use today have 8-bit bytes.) -

- -

-SoftFloat is written in C and is designed to work with other C code. -The C compiler used must conform at a minimum to the 1989 ANSI standard for the -C language (same as the 1990 ISO standard) and must in addition support basic -arithmetic on 64-bit integers. -Earlier releases of SoftFloat included implementations of 32-bit -single-precision and 64-bit double-precision floating-point that -did not require 64-bit integers, but this option is not supported -starting with Release 3. -Since 1999, ISO standards for C have mandated compiler support for -64-bit integers. -A compiler conforming to the 1999 C Standard or later is recommended but not -strictly required. -

- -

-Most operations not required by the original 1985 version of the IEEE -Floating-Point Standard but added in the 2008 version are not yet supported in -SoftFloat Release 3e. -

- - -

3. Acknowledgments and License

- -

-The SoftFloat package was written by me, John R. Hauser. -Release 3 of SoftFloat was a completely new implementation -supplanting earlier releases. -The project to create Release 3 (now through 3e) was -done in the employ of the University of California, Berkeley, within the -Department of Electrical Engineering and Computer Sciences, first for the -Parallel Computing Laboratory (Par Lab) and then for the ASPIRE Lab. -The work was officially overseen by Prof. Krste Asanovic, with funding provided -by these sources: -

- ---- - - - - - - - - - -
Par Lab: -Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery -(Award #DIG07-10227), with additional support from Par Lab affiliates Nokia, -NVIDIA, Oracle, and Samsung. -
ASPIRE Lab: -DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from -ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA, -Oracle, and Samsung. -
-
-

- -

-The following applies to the whole of SoftFloat Release 3e as well -as to each source file individually. -

- -

-Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. -All rights reserved. -

- -

-Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -

    - -
  1. -

    -Redistributions of source code must retain the above copyright notice, this -list of conditions, and the following disclaimer. -

    - -
  2. -

    -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions, and the following disclaimer in the documentation and/or -other materials provided with the distribution. -

    - -
  3. -

    -Neither the name of the University nor the names of its contributors may be -used to endorse or promote products derived from this software without specific -prior written permission. -

    - -
-

- -

-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS”, -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. -IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -

- - -

4. Types and Functions

- -

-The types and functions of SoftFloat are declared in header file -softfloat.h. -

- -

4.1. Boolean and Integer Types

- -

-Header file softfloat.h depends on standard headers -<stdbool.h> and <stdint.h> to define type -bool and several integer types. -These standard headers have been part of the ISO C Standard Library since 1999. -With any recent compiler, they are likely to be supported, even if the compiler -does not claim complete conformance to the latest ISO C Standard. -For older or nonstandard compilers, a port of SoftFloat may have substitutes -for these headers. -Header softfloat.h depends only on the name bool from -<stdbool.h> and on these type names from -<stdint.h>: -

-
-uint16_t
-uint32_t
-uint64_t
-int32_t
-int64_t
-uint_fast8_t
-uint_fast32_t
-uint_fast64_t
-int_fast32_t
-int_fast64_t
-
-
-

- - -

4.2. Floating-Point Types

- -

-The softfloat.h header defines five floating-point types: -

- - - - - - - - - - - - - - - - - - - - - -
float16_t16-bit half-precision binary format
float32_t32-bit single-precision binary format
float64_t64-bit double-precision binary format
extFloat80_t   80-bit double-extended-precision binary format (old Intel or -Motorola format)
float128_t128-bit quadruple-precision binary format
-
-The non-extended types are each exactly the size specified: -16 bits for float16_t, 32 bits for -float32_t, 64 bits for float64_t, and -128 bits for float128_t. -Aside from these size requirements, the definitions of all these types may -differ for different ports of SoftFloat to specific systems. -A given port of SoftFloat may or may not define some of the floating-point -types as aliases for the C standard types float, -double, and long double. -

- -

-Header file softfloat.h also defines a structure, -struct extFloat80M, for the representation of -80-bit double-extended-precision floating-point values in memory. -This structure is the same size as type extFloat80_t and contains -at least these two fields (not necessarily in this order): -

-
-uint16_t signExp;
-uint64_t signif;
-
-
-Field signExp contains the sign and exponent of the floating-point -value, with the sign in the most significant bit (bit 15) and the -encoded exponent in the other 15 bits. -Field signif is the complete 64-bit significand of -the floating-point value. -(In the usual encoding for 80-bit extended floating-point, the -leading 1 bit of normalized numbers is not implicit but is stored -in the most significant bit of the significand.) -

- -

4.3. Supported Floating-Point Functions

- -

-SoftFloat implements these arithmetic operations for its floating-point types: -

    -
  • -conversions between any two floating-point formats; -
  • -for each floating-point format, conversions to and from signed and unsigned -32-bit and 64-bit integers; -
  • -for each format, the usual addition, subtraction, multiplication, division, and -square root operations; -
  • -for each format except extFloat80_t, the fused multiply-add -operation defined by the IEEE Standard; -
  • -for each format, the floating-point remainder operation defined by the IEEE -Standard; -
  • -for each format, a “round to integer” operation that rounds to the -nearest integer value in the same format; and -
  • -comparisons between two values in the same floating-point format. -
-

- -

-The following operations required by the 2008 IEEE Floating-Point Standard are -not supported in SoftFloat Release 3e: -

    -
  • -nextUp, nextDown, minNum, maxNum, minNumMag, -maxNumMag, scaleB, and logB; -
  • -conversions between floating-point formats and decimal or hexadecimal character -sequences; -
  • -all “quiet-computation” operations (copy, negate, -abs, and copySign, which all involve only simple copying and/or -manipulation of the floating-point sign bit); and -
  • -all “non-computational” operations other than isSignaling -(which is supported). -
-

- -

4.4. Non-canonical Representations in extFloat80_t

- -

-Because the 80-bit double-extended-precision format, -extFloat80_t, stores an explicit leading significand bit, many -finite floating-point numbers are encodable in this type in multiple equivalent -forms. -Of these multiple encodings, there is always a unique one with the least -encoded exponent value, and this encoding is considered the canonical -representation of the floating-point number. -Any other equivalent representations (having a higher encoded exponent value) -are non-canonical. -For a value in the subnormal range (including zero), the canonical -representation always has an encoded exponent of zero and a leading significand -bit of 0. -For finite values outside the subnormal range, the canonical representation -always has an encoded exponent that is nonzero and a leading significand bit -of 1. -

- -

-For an infinity or NaN, the leading significand bit is similarly expected to -be 1. -An infinity or NaN with a leading significand bit of 0 is again -considered non-canonical. -Hence, altogether, to be canonical, a value of type extFloat80_t -must have a leading significand bit of 1, unless the value is -subnormal or zero, in which case the leading significand bit and the encoded -exponent must both be zero. -

- -

-SoftFloat’s functions are not guaranteed to operate as expected when -inputs of type extFloat80_t are non-canonical. -Assuming all of a function’s extFloat80_t inputs (if any) -are canonical, function outputs of type extFloat80_t will always -be canonical. -

- -

4.5. Conventions for Passing Arguments and Results

- -

-Values that are at most 64 bits in size (i.e., not the -80-bit or 128-bit floating-point formats) are in all -cases passed as function arguments by value. -Likewise, when an output of a function is no more than 64 bits, it -is always returned directly as the function result. -Thus, for example, the SoftFloat function for adding two 64-bit -floating-point values has this simple signature: -

-float64_t f64_add( float64_t, float64_t ); -
-

- -

-The story is more complex when function inputs and outputs are -80-bit and 128-bit floating-point. -For these types, SoftFloat always provides a function that passes these larger -values into or out of the function indirectly, via pointers. -For example, for adding two 128-bit floating-point values, -SoftFloat supplies this function: -

-void f128M_add( const float128_t *, const float128_t *, float128_t * ); -
-The first two arguments point to the values to be added, and the last argument -points to the location where the sum will be stored. -The M in the name f128M_add is mnemonic for the fact -that the 128-bit inputs and outputs are “in memory”, -pointed to by pointer arguments. -

- -

-All ports of SoftFloat implement these pass-by-pointer functions for -types extFloat80_t and float128_t. -At the same time, SoftFloat ports may also implement alternate versions of -these same functions that pass extFloat80_t and -float128_t by value, like the smaller formats. -Thus, besides the function with name f128M_add shown above, a -SoftFloat port may also supply an equivalent function with this signature: -

-float128_t f128_add( float128_t, float128_t ); -
-

- -

-As a general rule, on computers where the machine word size is -32 bits or smaller, only the pass-by-pointer versions of functions -(e.g., f128M_add) are provided for types extFloat80_t -and float128_t, because passing such large types directly can have -significant extra cost. -On computers where the word size is 64 bits or larger, both -function versions (f128M_add and f128_add) are -provided, because the cost of passing by value is then more reasonable. -Applications that must be portable accross both classes of computers must use -the pointer-based functions, as these are always implemented. -However, if it is known that SoftFloat includes the by-value functions for all -platforms of interest, programmers can use whichever version they prefer. -

- - -

5. Reserved Names

- -

-In addition to the variables and functions documented here, SoftFloat defines -some symbol names for its own private use. -These private names always begin with the prefix -‘softfloat_’. -When a program includes header softfloat.h or links with the -SoftFloat library, all names with prefix ‘softfloat_’ -are reserved for possible use by SoftFloat. -Applications that use SoftFloat should not define their own names with this -prefix, and should reference only such names as are documented. -

- - -

6. Mode Variables

- -

-The following global variables control rounding mode, underflow detection, and -the 80-bit extended format’s rounding precision: -

-softfloat_roundingMode
-softfloat_detectTininess
-extF80_roundingPrecision -
-These mode variables are covered in the next several subsections. -For some SoftFloat ports, these variables may be per-thread (declared -thread_local), meaning that different execution threads have their -own separate copies of the variables. -

- -

6.1. Rounding Mode

- -

-All five rounding modes defined by the 2008 IEEE Floating-Point Standard are -implemented for all operations that require rounding. -Some ports of SoftFloat may also implement the round-to-odd mode. -

- -

-The rounding mode is selected by the global variable -

-uint_fast8_t softfloat_roundingMode; -
-This variable may be set to one of the values -
- - - - - - - - - - - - - - - - - - - - - - - - - -
softfloat_round_near_evenround to nearest, with ties to even
softfloat_round_near_maxMag  round to nearest, with ties to maximum magnitude (away from zero)
softfloat_round_minMaground to minimum magnitude (toward zero)
softfloat_round_minround to minimum (down)
softfloat_round_maxround to maximum (up)
softfloat_round_oddround to odd (jamming), if supported by the SoftFloat port
-
-Variable softfloat_roundingMode is initialized to -softfloat_round_near_even. -

- -

-When softfloat_round_odd is the rounding mode for a function that -rounds to an integer value (either conversion to an integer format or a -‘roundToInt’ function), if the input is not already an -integer, the rounded result is the closest odd integer. -For other operations, this rounding mode acts as though the floating-point -result is first rounded to minimum magnitude, the same as -softfloat_round_minMag, and then, if the result is inexact, the -least-significant bit of the result is set to 1. -Rounding to odd is also known as jamming. -

- -

6.2. Underflow Detection

- -

-In the terminology of the IEEE Standard, SoftFloat can detect tininess for -underflow either before or after rounding. -The choice is made by the global variable -

-uint_fast8_t softfloat_detectTininess; -
-which can be set to either -
-softfloat_tininess_beforeRounding
-softfloat_tininess_afterRounding -
-Detecting tininess after rounding is usually better because it results in fewer -spurious underflow signals. -The other option is provided for compatibility with some systems. -Like most systems (and as required by the newer 2008 IEEE Standard), SoftFloat -always detects loss of accuracy for underflow as an inexact result. -

- -

6.3. Rounding Precision for the 80-Bit Extended Format

- -

-For extFloat80_t only, the rounding precision of the basic -arithmetic operations is controlled by the global variable -

-uint_fast8_t extF80_roundingPrecision; -
-The operations affected are: -
-extF80_add
-extF80_sub
-extF80_mul
-extF80_div
-extF80_sqrt -
-When extF80_roundingPrecision is set to its default value of 80, -these operations are rounded to the full precision of the 80-bit -double-extended-precision format, like occurs for other formats. -Setting extF80_roundingPrecision to 32 or to 64 causes the -operations listed to be rounded to 32-bit precision (equivalent to -float32_t) or to 64-bit precision (equivalent to -float64_t), respectively. -When rounding to reduced precision, additional bits in the result significand -beyond the rounding point are set to zero. -The consequences of setting extF80_roundingPrecision to a value -other than 32, 64, or 80 is not specified. -Operations other than the ones listed above are not affected by -extF80_roundingPrecision. -

- - -

7. Exceptions and Exception Flags

- -

-All five exception flags required by the IEEE Floating-Point Standard are -implemented. -Each flag is stored as a separate bit in the global variable -

-uint_fast8_t softfloat_exceptionFlags; -
-The positions of the exception flag bits within this variable are determined by -the bit masks -
-softfloat_flag_inexact
-softfloat_flag_underflow
-softfloat_flag_overflow
-softfloat_flag_infinite
-softfloat_flag_invalid -
-Variable softfloat_exceptionFlags is initialized to all zeros, -meaning no exceptions. -

- -

-For some SoftFloat ports, softfloat_exceptionFlags may be -per-thread (declared thread_local), meaning that different -execution threads have their own separate instances of it. -

- -

-An individual exception flag can be cleared with the statement -

-softfloat_exceptionFlags &= ~softfloat_flag_<exception>; -
-where <exception> is the appropriate name. -To raise a floating-point exception, function softfloat_raiseFlags -should normally be used. -

- -

-When SoftFloat detects an exception other than inexact, it calls -softfloat_raiseFlags. -The default version of this function simply raises the corresponding exception -flags. -Particular ports of SoftFloat may support alternate behavior, such as exception -traps, by modifying the default softfloat_raiseFlags. -A program may also supply its own softfloat_raiseFlags function to -override the one from the SoftFloat library. -

- -

-Because inexact results occur frequently under most circumstances (and thus are -hardly exceptional), SoftFloat does not ordinarily call -softfloat_raiseFlags for inexact exceptions. -It does always raise the inexact exception flag as required. -

- - -

8. Function Details

- -

-In this section, <float> appears in function names as -a substitute for one of these abbreviations: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
f16indicates float16_t, passed by value
f32indicates float32_t, passed by value
f64indicates float64_t, passed by value
extF80M   indicates extFloat80_t, passed indirectly via pointers
extF80indicates extFloat80_t, passed by value
f128Mindicates float128_t, passed indirectly via pointers
f128indicates float128_t, passed by value
-
-The circumstances under which values of floating-point types -extFloat80_t and float128_t may be passed either by -value or indirectly via pointers was discussed earlier in -section 4.5, Conventions for Passing Arguments and Results. -

- -

8.1. Conversions from Integer to Floating-Point

- -

-All conversions from a 32-bit or 64-bit integer, -signed or unsigned, to a floating-point format are supported. -Functions performing these conversions have these names: -

-ui32_to_<float>
-ui64_to_<float>
-i32_to_<float>
-i64_to_<float> -
-Conversions from 32-bit integers to 64-bit -double-precision and larger formats are always exact, and likewise conversions -from 64-bit integers to 80-bit -double-extended-precision and 128-bit quadruple-precision are also -always exact. -

- -

-Each conversion function takes one input of the appropriate type and generates -one output. -The following illustrates the signatures of these functions in cases when the -floating-point result is passed either by value or via pointers: -

-
-float64_t i32_to_f64( int32_t a );
-
-
-void i32_to_f128M( int32_t a, float128_t *destPtr );
-
-
-

- -

8.2. Conversions from Floating-Point to Integer

- -

-Conversions from a floating-point format to a 32-bit or -64-bit integer, signed or unsigned, are supported with these -functions: -

-<float>_to_ui32
-<float>_to_ui64
-<float>_to_i32
-<float>_to_i64 -
-The functions have signatures as follows, depending on whether the -floating-point input is passed by value or via pointers: -
-
-int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact );
-
-
-int_fast32_t
- f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact );
-
-
-

- -

-The roundingMode argument specifies the rounding mode for -the conversion. -The variable that usually indicates rounding mode, -softfloat_roundingMode, is ignored. -Argument exact determines whether the inexact -exception flag is raised if the conversion is not exact. -If exact is true, the inexact flag may -be raised; -otherwise, it will not be, even if the conversion is inexact. -

- -

-A conversion from floating-point to integer format raises the invalid -exception if the source value cannot be rounded to a representable integer of -the desired size (32 or 64 bits). -In such circumstances, the integer result returned is determined by the -particular port of SoftFloat, although typically this value will be either the -maximum or minimum value of the integer format. -The functions that convert to integer types never raise the floating-point -overflow exception. -

- -

-Because languages such as C require that conversions to integers -be rounded toward zero, the following functions are provided for improved speed -and convenience: -

-<float>_to_ui32_r_minMag
-<float>_to_ui64_r_minMag
-<float>_to_i32_r_minMag
-<float>_to_i64_r_minMag -
-These functions round only toward zero (to minimum magnitude). -The signatures for these functions are the same as above without the redundant -roundingMode argument: -
-
-int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact );
-
-
-int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact );
-
-
-

- -

8.3. Conversions Among Floating-Point Types

- -

-Conversions between floating-point formats are done by functions with these -names: -

-<float>_to_<float> -
-All combinations of source and result type are supported where the source and -result are different formats. -There are four different styles of signature for these functions, depending on -whether the input and the output floating-point values are passed by value or -via pointers: -
-
-float32_t f64_to_f32( float64_t a );
-
-
-float32_t f128M_to_f32( const float128_t *aPtr );
-
-
-void f32_to_f128M( float32_t a, float128_t *destPtr );
-
-
-void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *destPtr );
-
-
-

- -

-Conversions from a smaller to a larger floating-point format are always exact -and so require no rounding. -

- -

8.4. Basic Arithmetic Functions

- -

-The following basic arithmetic functions are provided: -

-<float>_add
-<float>_sub
-<float>_mul
-<float>_div
-<float>_sqrt -
-Each floating-point operation takes two operands, except for sqrt -(square root) which takes only one. -The operands and result are all of the same floating-point format. -Signatures for these functions take the following forms: -
-
-float64_t f64_add( float64_t a, float64_t b );
-
-
-void
- f128M_add(
-     const float128_t *aPtr, const float128_t *bPtr, float128_t *destPtr );
-
-
-float64_t f64_sqrt( float64_t a );
-
-
-void f128M_sqrt( const float128_t *aPtr, float128_t *destPtr );
-
-
-When floating-point values are passed indirectly through pointers, arguments -aPtr and bPtr point to the input -operands, and the last argument, destPtr, points to the -location where the result is stored. -

- -

-Rounding of the 80-bit double-extended-precision -(extFloat80_t) functions is affected by variable -extF80_roundingPrecision, as explained earlier in -section 6.3, -Rounding Precision for the 80-Bit Extended Format. -

- -

8.5. Fused Multiply-Add Functions

- -

-The 2008 version of the IEEE Floating-Point Standard defines a fused -multiply-add operation that does a combined multiplication and addition -with only a single rounding. -SoftFloat implements fused multiply-add with functions -

-<float>_mulAdd -
-Unlike other operations, fused multiple-add is not supported for the -80-bit double-extended-precision format, -extFloat80_t. -

- -

-Depending on whether floating-point values are passed by value or via pointers, -the fused multiply-add functions have signatures of these forms: -

-
-float64_t f64_mulAdd( float64_t a, float64_t b, float64_t c );
-
-
-void
- f128M_mulAdd(
-     const float128_t *aPtr,
-     const float128_t *bPtr,
-     const float128_t *cPtr,
-     float128_t *destPtr
- );
-
-
-The functions compute -(a × b) - + c -with a single rounding. -When floating-point values are passed indirectly through pointers, arguments -aPtr, bPtr, and -cPtr point to operands a, -b, and c respectively, and -destPtr points to the location where the result is stored. -

- -

-If one of the multiplication operands a and -b is infinite and the other is zero, these functions raise -the invalid exception even if operand c is a quiet NaN. -

- -

8.6. Remainder Functions

- -

-For each format, SoftFloat implements the remainder operation defined by the -IEEE Floating-Point Standard. -The remainder functions have names -

-<float>_rem -
-Each remainder operation takes two floating-point operands of the same format -and returns a result in the same format. -Depending on whether floating-point values are passed by value or via pointers, -the remainder functions have signatures of these forms: -
-
-float64_t f64_rem( float64_t a, float64_t b );
-
-
-void
- f128M_rem(
-     const float128_t *aPtr, const float128_t *bPtr, float128_t *destPtr );
-
-
-When floating-point values are passed indirectly through pointers, arguments -aPtr and bPtr point to operands -a and b respectively, and -destPtr points to the location where the result is stored. -

- -

-The IEEE Standard remainder operation computes the value -a - − n × b, -where n is the integer closest to -a ÷ b. -If a ÷ b is exactly -halfway between two integers, n is the even integer closest to -a ÷ b. -The IEEE Standard’s remainder operation is always exact and so requires -no rounding. -

- -

-Depending on the relative magnitudes of the operands, the remainder -functions can take considerably longer to execute than the other SoftFloat -functions. -This is an inherent characteristic of the remainder operation itself and is not -a flaw in the SoftFloat implementation. -

- -

8.7. Round-to-Integer Functions

- -

-For each format, SoftFloat implements the round-to-integer operation specified -by the IEEE Floating-Point Standard. -These functions are named -

-<float>_roundToInt -
-Each round-to-integer operation takes a single floating-point operand. -This operand is rounded to an integer according to a specified rounding mode, -and the resulting integer value is returned in the same floating-point format. -(Note that the result is not an integer type.) -

- -

-The signatures of the round-to-integer functions are similar to those for -conversions to an integer type: -

-
-float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact );
-
-
-void
- f128M_roundToInt(
-     const float128_t *aPtr,
-     uint_fast8_t roundingMode,
-     bool exact,
-     float128_t *destPtr
- );
-
-
-When floating-point values are passed indirectly through pointers, -aPtr points to the input operand and -destPtr points to the location where the result is stored. -

- -

-The roundingMode argument specifies the rounding mode to -apply. -The variable that usually indicates rounding mode, -softfloat_roundingMode, is ignored. -Argument exact determines whether the inexact -exception flag is raised if the conversion is not exact. -If exact is true, the inexact flag may -be raised; -otherwise, it will not be, even if the conversion is inexact. -

- -

8.8. Comparison Functions

- -

-For each format, the following floating-point comparison functions are -provided: -

-<float>_eq
-<float>_le
-<float>_lt -
-Each comparison takes two operands of the same type and returns a Boolean. -The abbreviation eq stands for “equal” (=); -le stands for “less than or equal” (≤); -and lt stands for “less than” (<). -Depending on whether the floating-point operands are passed by value or via -pointers, the comparison functions have signatures of these forms: -
-
-bool f64_eq( float64_t a, float64_t b );
-
-
-bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr );
-
-
-

- -

-The usual greater-than (>), greater-than-or-equal (≥), and not-equal -(≠) comparisons are easily obtained from the functions provided. -The not-equal function is just the logical complement of the equal function. -The greater-than-or-equal function is identical to the less-than-or-equal -function with the arguments in reverse order, and likewise the greater-than -function is identical to the less-than function with the arguments reversed. -

- -

-The IEEE Floating-Point Standard specifies that the less-than-or-equal and -less-than comparisons by default raise the invalid exception if either -operand is any kind of NaN. -Equality comparisons, on the other hand, are defined by default to raise the -invalid exception only for signaling NaNs, not quiet NaNs. -For completeness, SoftFloat provides these complementary functions: -

-<float>_eq_signaling
-<float>_le_quiet
-<float>_lt_quiet -
-The signaling equality comparisons are identical to the default -equality comparisons except that the invalid exception is raised for any -NaN input, not just for signaling NaNs. -Similarly, the quiet comparison functions are identical to their -default counterparts except that the invalid exception is not raised for -quiet NaNs. -

- -

8.9. Signaling NaN Test Functions

- -

-Functions for testing whether a floating-point value is a signaling NaN are -provided with these names: -

-<float>_isSignalingNaN -
-The functions take one floating-point operand and return a Boolean indicating -whether the operand is a signaling NaN. -Accordingly, the functions have the forms -
-
-bool f64_isSignalingNaN( float64_t a );
-
-
-bool f128M_isSignalingNaN( const float128_t *aPtr );
-
-
-

- -

8.10. Raise-Exception Function

- -

-SoftFloat provides a single function for raising floating-point exceptions: -

-
-void softfloat_raiseFlags( uint_fast8_t exceptions );
-
-
-The exceptions argument is a mask indicating the set of -exceptions to raise. -(See earlier section 7, Exceptions and Exception Flags.) -In addition to setting the specified exception flags in variable -softfloat_exceptionFlags, the softfloat_raiseFlags -function may cause a trap or abort appropriate for the current system. -

- - -

9. Changes from SoftFloat Release 2

- -

-Apart from a change in the legal use license, Release 3 of -SoftFloat introduced numerous technical differences compared to earlier -releases. -

- -

9.1. Name Changes

- -

-The most obvious and pervasive difference compared to Release 2 -is that the names of most functions and variables have changed, even when the -behavior has not. -First, the floating-point types, the mode variables, the exception flags -variable, the function to raise exceptions, and various associated constants -have been renamed as follows: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
old name, Release 2:new name, Release 3:
float32float32_t
float64float64_t
floatx80extFloat80_t
float128float128_t
float_rounding_modesoftfloat_roundingMode
float_round_nearest_evensoftfloat_round_near_even
float_round_to_zerosoftfloat_round_minMag
float_round_downsoftfloat_round_min
float_round_upsoftfloat_round_max
float_detect_tininesssoftfloat_detectTininess
float_tininess_before_rounding    softfloat_tininess_beforeRounding
float_tininess_after_roundingsoftfloat_tininess_afterRounding
floatx80_rounding_precisionextF80_roundingPrecision
float_exception_flagssoftfloat_exceptionFlags
float_flag_inexactsoftfloat_flag_inexact
float_flag_underflowsoftfloat_flag_underflow
float_flag_overflowsoftfloat_flag_overflow
float_flag_divbyzerosoftfloat_flag_infinite
float_flag_invalidsoftfloat_flag_invalid
float_raisesoftfloat_raiseFlags
-
-

- -

-Furthermore, Release 3 adopted the following new abbreviations for -function names: -

- - - - - - - - - - - -
used in names in Release 2:    used in names in Release 3:
int32 i32
int64 i64
float32 f32
float64 f64
floatx80 extF80
float128 f128
-
-Thus, for example, the function to add two 32-bit floating-point -numbers, previously called float32_add in Release 2, -is now f32_add. -Lastly, there have been a few other changes to function names: -
- - - - - - - - - - - - - - - - - - - - - -
used in names in Release 2:   used in names in Release 3:   relevant functions:
_round_to_zero_r_minMagconversions from floating-point to integer (section 8.2)
round_to_introundToIntround-to-integer functions (section 8.7)
is_signaling_nan    isSignalingNaNsignaling NaN test functions (section 8.9)
-
-

- -

9.2. Changes to Function Arguments

- -

-Besides simple name changes, some operations were given a different interface -in Release 3 than they had in Release 2: -

    - -
  • -

    -Since Release 3, integer arguments and results of functions have -standard types from header <stdint.h>, such as -uint32_t, whereas previously their types could be defined -differently for each port of SoftFloat, usually using traditional C types such -as unsigned int. -Likewise, functions in Release 3 and later pass Booleans as -standard type bool from <stdbool.h>, whereas -previously these were again passed as a port-specific type (usually -int). -

    - -
  • -

    -As explained earlier in section 4.5, Conventions for Passing -Arguments and Results, SoftFloat functions in Release 3 and -later may pass 80-bit and 128-bit floating-point -values through pointers, meaning that functions take pointer arguments and then -read or write floating-point values at the locations indicated by the pointers. -In Release 2, floating-point arguments and results were always -passed by value, regardless of their size. -

    - -
  • -

    -Functions that round to an integer have additional -roundingMode and exact arguments that -they did not have in Release 2. -Refer to sections 8.2 and 8.7 for descriptions of these functions -since Release 3. -For Release 2, the rounding mode, when needed, was taken from the -same global variable that affects the basic arithmetic operations (now called -softfloat_roundingMode but previously known as -float_rounding_mode). -Also, for Release 2, if the original floating-point input was not -an exact integer value, and if the invalid exception was not raised by -the function, the inexact exception was always raised. -Release 2 had no option to suppress raising inexact in this -case. -Applications using SoftFloat Release 3 or later can get the same -effect as Release 2 by passing variable -softfloat_roundingMode for argument -roundingMode and true for argument -exact. -

    - -
-

- -

9.3. Added Capabilities

- -

-With Release 3, some new features have been added that were not -present in Release 2: -

    - -
  • -

    -A port of SoftFloat can now define any of the floating-point types -float32_t, float64_t, extFloat80_t, and -float128_t as aliases for C’s standard floating-point types -float, double, and long -double, using either #define or typedef. -This potential convenience was not supported under Release 2. -

    - -

    -(Note, however, that there may be a performance cost to defining -SoftFloat’s floating-point types this way, depending on the platform and -the applications using SoftFloat. -Ports of SoftFloat may choose to forgo the convenience in favor of better -speed.) -

    - -

    -

  • -As of Release 3b, 16-bit half-precision, -float16_t, is supported. -

    - -

    -

  • -Functions have been added for converting between the floating-point types and -unsigned integers. -Release 2 supported only signed integers, not unsigned. -

    - -

    -

  • -Fused multiply-add functions have been added for all floating-point formats -except 80-bit double-extended-precision, -extFloat80_t. -

    - -

    -

  • -New rounding modes are supported: -softfloat_round_near_maxMag (round to nearest, with ties to -maximum magnitude, away from zero), and, as of Release 3c, -optional softfloat_round_odd (round to odd, also known as -jamming). -

    - -
-

- -

9.4. Better Compatibility with the C Language

- -

-Release 3 of SoftFloat was written to conform better to the ISO C -Standard’s rules for portability. -For example, older releases of SoftFloat employed type conversions in ways -that, while commonly practiced, are not fully defined by the C Standard. -Such problematic type conversions have generally been replaced by the use of -unions, the behavior around which is more strictly regulated these days. -

- -

9.5. New Organization as a Library

- -

-Starting with Release 3, SoftFloat now builds as a library. -Previously, SoftFloat compiled into a single, monolithic object file containing -all the SoftFloat functions, with the consequence that a program linking with -SoftFloat would get every SoftFloat function in its binary file even if only a -few functions were actually used. -With SoftFloat in the form of a library, a program that is linked by a standard -linker will include only those functions of SoftFloat that it needs and no -others. -

- -

9.6. Optimization Gains (and Losses)

- -

-Individual SoftFloat functions have been variously improved in -Release 3 compared to earlier releases. -In particular, better, faster algorithms have been deployed for the operations -of division, square root, and remainder. -For functions operating on the larger 80-bit and -128-bit formats, extFloat80_t and -float128_t, code size has also generally been reduced. -

- -

-However, because Release 2 compiled all of SoftFloat together as a -single object file, compilers could make optimizations across function calls -when one SoftFloat function calls another. -Now that the functions of SoftFloat are compiled separately and only afterward -linked together into a program, there is not usually the same opportunity to -optimize across function calls. -Some loss of speed has been observed due to this change. -

- - -

10. Future Directions

- -

-The following improvements are anticipated for future releases of SoftFloat: -

    -
  • -more functions from the 2008 version of the IEEE Floating-Point Standard; -
  • -consistent, defined behavior for non-canonical representations of extended -format extFloat80_t (discussed in section 4.4, -Non-canonical Representations in extFloat80_t). - -
-

- - -

11. Contact Information

- -

-At the time of this writing, the most up-to-date information about SoftFloat -and the latest release can be found at the Web page -http://www.jhauser.us/arithmetic/SoftFloat.html. -

- - - - diff --git a/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c deleted file mode 100644 index 3405b3ba4efb..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| `zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c deleted file mode 100644 index cb7424f430c9..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c deleted file mode 100644 index e7ea80258916..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by `zWPtr'. Argument -| `zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c deleted file mode 100644 index 7a9423bea290..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c deleted file mode 100644 index d4e458a94143..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c deleted file mode 100644 index ed6c2268f31f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c deleted file mode 100644 index 1182be3c9cdf..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c deleted file mode 100644 index 00baf35f893a..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by `zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c deleted file mode 100644 index ab6311ef2906..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c deleted file mode 100644 index 55ec25b58c8d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument `aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c deleted file mode 100644 index f838f02aaf1f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c deleted file mode 100644 index c1e242d23684..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c deleted file mode 100644 index b21ba660398d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c deleted file mode 100644 index 6529d2ee5fd1..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c deleted file mode 100644 index ea1d57a78814..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,107 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by `aSPtr' and `bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by `zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - bool isSigNaNA; - const struct extFloat80M *sPtr; - bool isSigNaNB; - uint_fast16_t uiB64; - uint64_t uiB0; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiMagA64, uiMagB64; - - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - sPtr = aSPtr; - if ( ! bSPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - uiB64 = bSPtr->signExp; - if ( isSigNaNB ) goto returnLargerUIMag; - uiB0 = bSPtr->signif; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto copyB; - goto copy; - } else { - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto copy; - goto copyB; - } - } - uiB64 = bSPtr->signExp; - returnLargerUIMag: - uiA64 = aSPtr->signExp; - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto copyB; - if ( uiMagB64 < uiMagA64 ) goto copy; - uiA0 = aSPtr->signif; - uiB0 = bSPtr->signif; - if ( uiA0 < uiB0 ) goto copyB; - if ( uiB0 < uiA0 ) goto copy; - if ( uiA64 < uiB64 ) goto copy; - copyB: - sPtr = bSPtr; - copy: - zSPtr->signExp = sPtr->signExp; - zSPtr->signif = sPtr->signif | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c deleted file mode 100644 index cc3f0f42c55d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA0, uiNonsigB0; - uint_fast16_t uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNExtF80UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA0 = uiA0 | UINT64_C( 0xC000000000000000 ); - uiNonsigB0 = uiB0 | UINT64_C( 0xC000000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiA64 < uiB64 ) goto returnA; - returnB: - uiZ.v64 = uiB64; - uiZ.v0 = uiNonsigB0; - return uiZ; - returnA: - uiZ.v64 = uiA64; - uiZ.v0 = uiNonsigA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c deleted file mode 100644 index aa903bf80909..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c +++ /dev/null @@ -1,76 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by `zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr', -| and `zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - bool isSigNaNA; - const uint32_t *ptr; - - ptr = aWPtr; - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - if ( - isSigNaNA - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto copy; - } - if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr; - copy: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c deleted file mode 100644 index 1c1c2f4a0983..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c +++ /dev/null @@ -1,81 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating `uiA64' and -| `uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating `uiB64' and `uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - } - if ( isNaNF128UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v64 |= UINT64_C( 0x0000800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c deleted file mode 100644 index 4e87ff41f806..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | 0x0200; - } - return (isNaNF16UI( uiA ) ? uiA : uiB) | 0x0200; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c deleted file mode 100644 index e1a87552506f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | 0x00400000; - } - return (isNaNF32UI( uiA ) ? uiA : uiB) | 0x00400000; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c deleted file mode 100644 index 1af349f3e324..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | UINT64_C( 0x0008000000000000 ); - } - return (isNaNF64UI( uiA ) ? uiA : uiB) | UINT64_C( 0x0008000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c deleted file mode 100644 index 3115306beedd..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by `flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply `softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/specialize.h b/deps/SoftFloat-3e/source/8086-SSE/specialize.h deleted file mode 100644 index 5fe119a1e1f1..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_afterRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0xFFFFFFFF -#define ui32_fromNaN 0xFFFFFFFF -#define i32_fromPosOverflow (-0x7FFFFFFF - 1) -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN (-0x7FFFFFFF - 1) - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0xFE00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0xFFC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0xFFFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0xFFFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c deleted file mode 100644 index 3405b3ba4efb..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| `zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c deleted file mode 100644 index cb7424f430c9..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c deleted file mode 100644 index e7ea80258916..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by `zWPtr'. Argument -| `zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c deleted file mode 100644 index 7a9423bea290..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c deleted file mode 100644 index d4e458a94143..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c deleted file mode 100644 index ed6c2268f31f..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c deleted file mode 100644 index 1182be3c9cdf..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c deleted file mode 100644 index 00baf35f893a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by `zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c deleted file mode 100644 index ab6311ef2906..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c deleted file mode 100644 index 55ec25b58c8d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument `aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c deleted file mode 100644 index f838f02aaf1f..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c deleted file mode 100644 index c1e242d23684..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c deleted file mode 100644 index b21ba660398d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c deleted file mode 100644 index 6529d2ee5fd1..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c deleted file mode 100644 index ea1d57a78814..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,107 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by `aSPtr' and `bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by `zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - bool isSigNaNA; - const struct extFloat80M *sPtr; - bool isSigNaNB; - uint_fast16_t uiB64; - uint64_t uiB0; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiMagA64, uiMagB64; - - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - sPtr = aSPtr; - if ( ! bSPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - uiB64 = bSPtr->signExp; - if ( isSigNaNB ) goto returnLargerUIMag; - uiB0 = bSPtr->signif; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto copyB; - goto copy; - } else { - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto copy; - goto copyB; - } - } - uiB64 = bSPtr->signExp; - returnLargerUIMag: - uiA64 = aSPtr->signExp; - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto copyB; - if ( uiMagB64 < uiMagA64 ) goto copy; - uiA0 = aSPtr->signif; - uiB0 = bSPtr->signif; - if ( uiA0 < uiB0 ) goto copyB; - if ( uiB0 < uiA0 ) goto copy; - if ( uiA64 < uiB64 ) goto copy; - copyB: - sPtr = bSPtr; - copy: - zSPtr->signExp = sPtr->signExp; - zSPtr->signif = sPtr->signif | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c deleted file mode 100644 index cc3f0f42c55d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA0, uiNonsigB0; - uint_fast16_t uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNExtF80UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA0 = uiA0 | UINT64_C( 0xC000000000000000 ); - uiNonsigB0 = uiB0 | UINT64_C( 0xC000000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiA64 < uiB64 ) goto returnA; - returnB: - uiZ.v64 = uiB64; - uiZ.v0 = uiNonsigB0; - return uiZ; - returnA: - uiZ.v64 = uiA64; - uiZ.v0 = uiNonsigA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c deleted file mode 100644 index 06554fbfe1ec..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c +++ /dev/null @@ -1,108 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by `zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr', -| and `zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - bool isSigNaNA; - const uint32_t *ptr; - bool isSigNaNB; - uint32_t uiA96, uiB96, wordMagA, wordMagB; - - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - ptr = aWPtr; - if ( ! bWPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = f128M_isSignalingNaN( (const float128_t *) bWPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerUIMag; - if ( softfloat_isNaNF128M( bWPtr ) ) goto copyB; - goto copy; - } else { - if ( softfloat_isNaNF128M( aWPtr ) ) goto copy; - goto copyB; - } - } - returnLargerUIMag: - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - wordMagA = uiA96 & 0x7FFFFFFF; - wordMagB = uiB96 & 0x7FFFFFFF; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 2 )]; - wordMagB = bWPtr[indexWord( 4, 2 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 1 )]; - wordMagB = bWPtr[indexWord( 4, 1 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 0 )]; - wordMagB = bWPtr[indexWord( 4, 0 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - if ( uiA96 < uiB96 ) goto copy; - copyB: - ptr = bWPtr; - copy: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c deleted file mode 100644 index 46b9f5f2c25a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c +++ /dev/null @@ -1,105 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA64, uiNonsigB64, uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNF128UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA64 = uiA64 | UINT64_C( 0x0000800000000000 ); - uiNonsigB64 = uiB64 | UINT64_C( 0x0000800000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNF128UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNF128UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - uiMagB64 = uiB64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiNonsigA64 < uiNonsigB64 ) goto returnA; - returnB: - uiZ.v64 = uiNonsigB64; - uiZ.v0 = uiB0; - return uiZ; - returnA: - uiZ.v64 = uiNonsigA64; - uiZ.v0 = uiA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c deleted file mode 100644 index 89cc0fe97ea2..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast16_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - isSigNaNB = softfloat_isSigNaNF16UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | 0x0200; - uiNonsigB = uiB | 0x0200; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF16UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF16UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & 0x7FFF; - uiMagB = uiB & 0x7FFF; - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c deleted file mode 100644 index aeb6024acf96..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast32_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - isSigNaNB = softfloat_isSigNaNF32UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | 0x00400000; - uiNonsigB = uiB | 0x00400000; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF32UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF32UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & 0x7FFFFFFF; - uiMagB = uiB & 0x7FFFFFFF; - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c deleted file mode 100644 index dabad402482a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - isSigNaNB = softfloat_isSigNaNF64UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | UINT64_C( 0x0008000000000000 ); - uiNonsigB = uiB | UINT64_C( 0x0008000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF64UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF64UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - uiMagB = uiB & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c deleted file mode 100644 index 3115306beedd..000000000000 --- a/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by `flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply `softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/8086/specialize.h b/deps/SoftFloat-3e/source/8086/specialize.h deleted file mode 100644 index 5fe119a1e1f1..000000000000 --- a/deps/SoftFloat-3e/source/8086/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_afterRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0xFFFFFFFF -#define ui32_fromNaN 0xFFFFFFFF -#define i32_fromPosOverflow (-0x7FFFFFFF - 1) -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN (-0x7FFFFFFF - 1) - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0xFE00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0xFFC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0xFFFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0xFFFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c deleted file mode 100644 index 54a50dc3575b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat_types.h" - -#define softfloat_commonNaNToExtF80M softfloat_commonNaNToExtF80M -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c deleted file mode 100644 index 5b698f6645ad..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToExtF80UI softfloat_commonNaNToExtF80UI -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c deleted file mode 100644 index b22baa816be0..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToF128M softfloat_commonNaNToF128M -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c deleted file mode 100644 index 70f0cf1c6cfc..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToF128UI softfloat_commonNaNToF128UI -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c deleted file mode 100644 index 1c6510c7e3c5..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - uint_fast16_t ui64; - uint_fast64_t ui0; - - ui64 = aSPtr->signExp; - ui0 = aSPtr->signif; - if ( - softfloat_isSigNaNExtF80UI( ui64, ui0 ) - || (bSPtr - && (ui64 = bSPtr->signExp, - ui0 = bSPtr->signif, - softfloat_isSigNaNExtF80UI( ui64, ui0 ))) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c deleted file mode 100644 index e1bb1555aa73..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - struct uint128 uiZ; - - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c deleted file mode 100644 index 9bddee955d56..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - - if ( - f128M_isSignalingNaN( (const float128_t *) aWPtr ); - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c deleted file mode 100644 index 57fddd158adc..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - struct uint128 uiZ; - - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c deleted file mode 100644 index 0b08e003967b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF16UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c deleted file mode 100644 index cab740358e3b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF32UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c deleted file mode 100644 index 83b91d3a9d96..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF64UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c deleted file mode 100644 index 61046da3c05e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by 'flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply 'softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h deleted file mode 100644 index 2c481a259675..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h +++ /dev/null @@ -1,407 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_beforeRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0 -#define ui32_fromNaN 0 -#define i32_fromPosOverflow 0x7FFFFFFF -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN 0 - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow 0 -#define ui64_fromNaN 0 -#define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF ) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN 0 - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { char _unused; }; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0x7E00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f16UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x0200) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF16UI( aPtr ) ((uint_fast16_t) defaultNaNF16UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0x7FC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f32UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x00400000) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF32UI( aPtr ) ((uint_fast32_t) defaultNaNF32UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f64UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & UINT64_C( 0x0008000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF64UI( aPtr ) ((uint_fast64_t) defaultNaNF64UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0x7FFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_extF80UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA0) & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToExtF80UI -INLINE -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; -} -#else -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f128UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA64) & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToF128UI -INLINE -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; -} -#else -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); -#endif - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_extF80MToCommonNaN( aSPtr, zPtr ) if ( ! ((aSPtr)->signif & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToExtF80M -INLINE -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; -} -#else -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0x7FFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -#define softfloat_f128MToCommonNaN( aWPtr, zPtr ) if ( ! ((aWPtr)[indexWordHi( 4 )] & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToF128M -INLINE -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; -} -#else -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c deleted file mode 100644 index 543400bc1a92..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c deleted file mode 100644 index 6cf1d119186e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c deleted file mode 100644 index 4e8ede07fd01..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c deleted file mode 100644 index f938c3f2d37e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c deleted file mode 100644 index 6cd4fc192c2d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c deleted file mode 100644 index 7b38167f0022..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c deleted file mode 100644 index 14847029d28a..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c deleted file mode 100644 index 82216cf4111d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c deleted file mode 100644 index 2559fb6d2c3b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c deleted file mode 100644 index 322d25ab1e53..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c deleted file mode 100644 index 843c187a7da1..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c deleted file mode 100644 index f5fe58770d20..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c deleted file mode 100644 index 58726a357166..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c deleted file mode 100644 index 03761e4331c6..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c deleted file mode 100644 index f10ed0b62f11..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - const struct extFloat80M *sPtr; - bool isSigNaNA; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - - sPtr = aSPtr; - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - if ( - isSigNaNA - || (bSPtr - && extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto copyNonsig; - goto copyNonsigB; - } - uiZ64 = sPtr->signExp; - uiZ0 = sPtr->signif; - if ( isNaNExtF80UI( uiZ64, uiZ0 ) ) goto returnNonsig; - copyNonsigB: - sPtr = bSPtr; - copyNonsig: - uiZ64 = sPtr->signExp; - uiZ0 = sPtr->signif; - returnNonsig: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0 | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c deleted file mode 100644 index bd23c2473658..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - goto returnNonsigB; - } - if ( isNaNExtF80UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - returnNonsigB: - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v0 | UINT64_C( 0xC000000000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c deleted file mode 100644 index 23e766a1937f..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c +++ /dev/null @@ -1,77 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - const uint32_t *ptr; - bool isSigNaNA; - - ptr = aWPtr; - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - if ( - isSigNaNA - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( ! isSigNaNA ) ptr = bWPtr; - goto copyNonsig; - } - if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr; - copyNonsig: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c deleted file mode 100644 index b8882d77cfba..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - goto returnNonsigB; - } - if ( isNaNF128UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - returnNonsigB: - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v64 |= UINT64_C( 0x0000800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c deleted file mode 100644 index e333328746e6..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | 0x0200; - } - return isNaNF16UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c deleted file mode 100644 index c7508ae7cd1d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | 0x00400000; - } - return isNaNF32UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c deleted file mode 100644 index 8c67763818a1..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | UINT64_C( 0x0008000000000000 ); - } - return isNaNF64UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c deleted file mode 100644 index 61046da3c05e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by 'flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply 'softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h b/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h deleted file mode 100644 index 5321f33bcaad..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_beforeRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0 -#define ui32_fromNaN 0 -#define i32_fromPosOverflow 0x7FFFFFFF -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN 0 - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow 0 -#define ui64_fromNaN 0 -#define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF ) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN 0 - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0x7E00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0x7FC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0x7FFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0x7FFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_add.c b/deps/SoftFloat-3e/source/extF80M_add.c deleted file mode 100644 index 02e415fcc133..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_add.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_add( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - signA = signExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsExtF80 : softfloat_subMagsExtF80; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - extF80M_add( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - softfloat_addExtF80M( - (const struct extFloat80M *) aPtr, - (const struct extFloat80M *) bPtr, - (struct extFloat80M *) zPtr, - false - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_div.c b/deps/SoftFloat-3e/source/extF80M_div.c deleted file mode 100644 index 4d543ce9e510..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_div.c +++ /dev/null @@ -1,194 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_div( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_div( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_div( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA; - uint_fast16_t uiB64; - int32_t expB; - bool signZ; - uint64_t sigA, x64; - int32_t expZ; - int shiftDist; - uint32_t y[3], recip32, sigB[3]; - int ix; - uint32_t q, qs[2]; - uint_fast16_t uiZ64; - uint64_t uiZ0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( expA == 0x7FFF ) { - if ( expB == 0x7FFF ) goto invalid; - goto infinity; - } - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigA = aSPtr->signif; - x64 = bSPtr->signif; - if ( ! expB ) expB = 1; - if ( ! (x64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! x64 ) { - if ( ! sigA ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - expB += softfloat_normExtF80SigM( &x64 ); - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - expA += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFF; - shiftDist = 29; - if ( sigA < x64 ) { - --expZ; - shiftDist = 30; - } - softfloat_shortShiftLeft64To96M( sigA, shiftDist, y ); - recip32 = softfloat_approxRecip32_1( x64>>32 ); - sigB[indexWord( 3, 0 )] = (uint32_t) x64<<30; - x64 >>= 2; - sigB[indexWord( 3, 2 )] = x64>>32; - sigB[indexWord( 3, 1 )] = x64; - ix = 2; - for (;;) { - x64 = (uint64_t) y[indexWordHi( 3 )] * recip32; - q = (x64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - softfloat_remStep96MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 3 )] & 0x80000000 ) { - --q; - softfloat_add96M( y, sigB, y ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 0x3FFFFF) < 2 ) { - softfloat_remStep96MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 3 )] & 0x80000000 ) { - --q; - softfloat_add96M( y, sigB, y ); - } else if ( softfloat_compare96M( sigB, y ) <= 0 ) { - ++q; - softfloat_sub96M( y, sigB, y ); - } - if ( - y[indexWordLo( 3 )] || y[indexWord( 3, 1 )] || y[indexWord( 3, 2 )] - ) { - q |= 1; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - x64 = (uint64_t) q<<9; - y[indexWord( 3, 0 )] = x64; - x64 = ((uint64_t) qs[0]<<6) + (x64>>32); - y[indexWord( 3, 1 )] = x64; - y[indexWord( 3, 2 )] = (qs[1]<<3) + (x64>>32); - softfloat_roundPackMToExtF80M( - signZ, expZ, y, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_eq.c b/deps/SoftFloat-3e/source/extF80M_eq.c deleted file mode 100644 index e17aa24351e9..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_eq.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_eq( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( uiA0 == uiB0 ) { - return (uiA64 == uiB64) || ! uiA0; - } else { - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return ! softfloat_compareNonnormExtF80M( aSPtr, bSPtr ); - } - return false; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_eq_signaling.c b/deps/SoftFloat-3e/source/extF80M_eq_signaling.c deleted file mode 100644 index c4a7322393ad..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_eq_signaling.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_eq_signaling( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( uiA0 == uiB0 ) { - return (uiA64 == uiB64) || ! uiA0; - } else { - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return ! softfloat_compareNonnormExtF80M( aSPtr, bSPtr ); - } - return false; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_le.c b/deps/SoftFloat-3e/source/extF80M_le.c deleted file mode 100644 index e54eb9eea095..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_le.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_le( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA || ! (uiA0 | uiB0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) <= 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return true; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_le_quiet.c b/deps/SoftFloat-3e/source/extF80M_le_quiet.c deleted file mode 100644 index 943f262061bf..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_le_quiet.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_le_quiet( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA || ! (uiA0 | uiB0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) <= 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return true; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_lt.c b/deps/SoftFloat-3e/source/extF80M_lt.c deleted file mode 100644 index cbc562f64d7c..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_lt.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_lt( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA && ((uiA0 | uiB0) != 0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) < 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return false; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_lt_quiet.c b/deps/SoftFloat-3e/source/extF80M_lt_quiet.c deleted file mode 100644 index 650586d025a9..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_lt_quiet.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_lt_quiet( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA && ((uiA0 | uiB0) != 0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) < 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return false; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_mul.c b/deps/SoftFloat-3e/source/extF80M_mul.c deleted file mode 100644 index 281394f713f5..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_mul.c +++ /dev/null @@ -1,139 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_mul( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_mul( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_mul( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA; - uint_fast16_t uiB64; - int32_t expB; - bool signZ; - uint_fast16_t exp, uiZ64; - uint64_t uiZ0, sigA, sigB; - int32_t expZ; - uint32_t sigProd[4], *extSigZPtr; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( - (! aSPtr->signif && (expA != 0x7FFF)) - || (! bSPtr->signif && (expB != 0x7FFF)) - ) { - softfloat_invalidExtF80M( zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - sigA = aSPtr->signif; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - expA += softfloat_normExtF80SigM( &sigA ); - } - if ( ! expB ) expB = 1; - sigB = bSPtr->signif; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto zero; - expB += softfloat_normExtF80SigM( &sigB ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - softfloat_mul64To128M( sigA, sigB, sigProd ); - if ( sigProd[indexWordLo( 4 )] ) sigProd[indexWord( 4, 1 )] |= 1; - extSigZPtr = &sigProd[indexMultiwordHi( 4, 3 )]; - if ( sigProd[indexWordHi( 4 )] < 0x80000000 ) { - --expZ; - softfloat_add96M( extSigZPtr, extSigZPtr, extSigZPtr ); - } - softfloat_roundPackMToExtF80M( - signZ, expZ, extSigZPtr, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_rem.c b/deps/SoftFloat-3e/source/extF80M_rem.c deleted file mode 100644 index 4aff18ae9791..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_rem.c +++ /dev/null @@ -1,204 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_rem( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_rem( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_rem( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA, expB; - uint64_t x64; - bool signRem; - uint64_t sigA; - int32_t expDiff; - uint32_t rem[3], x[3], sig32B, q, recip32, rem2[3], *remPtr, *altRemPtr; - uint32_t *newRemPtr, wordMeanRem; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - expB = expExtF80UI64( bSPtr->signExp ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( expA == 0x7FFF ) goto invalid; - /*-------------------------------------------------------------------- - | If we get here, then argument b is an infinity and `expB' is 0x7FFF; - | Doubling `expB' is an easy way to ensure that `expDiff' later is - | less than -1, which will result in returning a canonicalized version - | of argument a. - *--------------------------------------------------------------------*/ - expB += expB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - x64 = bSPtr->signif; - if ( ! (x64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! x64 ) goto invalid; - expB += softfloat_normExtF80SigM( &x64 ); - } - signRem = signExtF80UI64( uiA64 ); - if ( ! expA ) expA = 1; - sigA = aSPtr->signif; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) { - expA = 0; - goto copyA; - } - expA += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < -1 ) goto copyA; - rem[indexWord( 3, 2 )] = sigA>>34; - rem[indexWord( 3, 1 )] = sigA>>2; - rem[indexWord( 3, 0 )] = (uint32_t) sigA<<30; - x[indexWord( 3, 0 )] = (uint32_t) x64<<30; - sig32B = x64>>32; - x64 >>= 2; - x[indexWord( 3, 2 )] = x64>>32; - x[indexWord( 3, 1 )] = x64; - if ( expDiff < 1 ) { - if ( expDiff ) { - --expB; - softfloat_add96M( x, x, x ); - q = 0; - } else { - q = (softfloat_compare96M( x, rem ) <= 0); - if ( q ) softfloat_sub96M( rem, x, rem ); - } - } else { - recip32 = softfloat_approxRecip32_1( sig32B ); - expDiff -= 30; - for (;;) { - x64 = (uint64_t) rem[indexWordHi( 3 )] * recip32; - if ( expDiff < 0 ) break; - q = (x64 + 0x80000000)>>32; - softfloat_remStep96MBy32( rem, 29, x, q, rem ); - if ( rem[indexWordHi( 3 )] & 0x80000000 ) { - softfloat_add96M( rem, x, rem ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (x64>>32)>>(~expDiff & 31); - softfloat_remStep96MBy32( rem, expDiff + 30, x, q, rem ); - if ( rem[indexWordHi( 3 )] & 0x80000000 ) { - remPtr = rem; - altRemPtr = rem2; - softfloat_add96M( remPtr, x, altRemPtr ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - remPtr = rem; - altRemPtr = rem2; - do { - ++q; - newRemPtr = altRemPtr; - softfloat_sub96M( remPtr, x, newRemPtr ); - altRemPtr = remPtr; - remPtr = newRemPtr; - } while ( ! (remPtr[indexWordHi( 3 )] & 0x80000000) ); - selectRem: - softfloat_add96M( remPtr, altRemPtr, x ); - wordMeanRem = x[indexWordHi( 3 )]; - if ( - (wordMeanRem & 0x80000000) - || (! wordMeanRem && (q & 1) && ! x[indexWord( 3, 0 )] - && ! x[indexWord( 3, 1 )]) - ) { - remPtr = altRemPtr; - } - if ( remPtr[indexWordHi( 3 )] & 0x80000000 ) { - signRem = ! signRem; - softfloat_negX96M( remPtr ); - } - softfloat_normRoundPackMToExtF80M( signRem, expB + 2, remPtr, 80, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - if ( expA < 1 ) { - sigA >>= 1 - expA; - expA = 0; - } - zSPtr->signExp = packToExtF80UI64( signRem, expA ); - zSPtr->signif = sigA; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_roundToInt.c b/deps/SoftFloat-3e/source/extF80M_roundToInt.c deleted file mode 100644 index 2e8572957110..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_roundToInt.c +++ /dev/null @@ -1,176 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_roundToInt( - const extFloat80_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - extFloat80_t *zPtr - ) -{ - - *zPtr = extF80_roundToInt( *aPtr, roundingMode, exact ); - -} - -#else - -void - extF80M_roundToInt( - const extFloat80_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - extFloat80_t *zPtr - ) -{ - const struct extFloat80M *aSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64, signUI64; - int32_t exp; - uint64_t sigA; - uint_fast16_t uiZ64; - uint64_t sigZ, lastBitMask, roundBitsMask; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - exp = expExtF80UI64( uiA64 ); - sigA = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( !(sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { - if ( !sigA ) { - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x3FFE ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( signUI64 ) goto mag1; - break; - case softfloat_round_max: - if ( !signUI64 ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - mag1: - uiZ64 = signUI64 | 0x3FFF; - sigZ = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x403E <= exp ) { - if ( exp == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_propagateNaNExtF80M( aSPtr, 0, zSPtr ); - return; - } - sigZ = UINT64_C( 0x8000000000000000 ); - } else { - sigZ = sigA; - } - uiZ64 = signUI64 | exp; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = signUI64 | exp; - lastBitMask = (uint64_t) 1<<(0x403E - exp); - roundBitsMask = lastBitMask - 1; - sigZ = sigA; - if ( roundingMode == softfloat_round_near_maxMag ) { - sigZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - sigZ += lastBitMask>>1; - if ( !(sigZ & roundBitsMask) ) sigZ &= ~lastBitMask; - } else if ( - roundingMode == (signUI64 ? softfloat_round_min : softfloat_round_max) - ) { - sigZ += roundBitsMask; - } - sigZ &= ~roundBitsMask; - if ( !sigZ ) { - ++uiZ64; - sigZ = UINT64_C( 0x8000000000000000 ); - } - if ( sigZ != sigA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sigZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = sigZ; - return; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_sqrt.c b/deps/SoftFloat-3e/source/extF80M_sqrt.c deleted file mode 100644 index 7ee91e0e5765..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_sqrt.c +++ /dev/null @@ -1,180 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_sqrt( *aPtr ); - -} - -#else - -void extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64, signUI64; - int32_t expA; - uint64_t rem64; - int32_t expZ; - uint32_t rem96[3], sig32A, recipSqrt32, sig32Z, q; - uint64_t sig64Z, x64; - uint32_t rem32, term[4], rem[4], extSigZ[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - expA = expExtF80UI64( uiA64 ); - rem64 = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( rem64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_propagateNaNExtF80M( aSPtr, 0, zSPtr ); - return; - } - if ( signUI64 ) goto invalid; - rem64 = UINT64_C( 0x8000000000000000 ); - goto copyA; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (rem64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! rem64 ) { - uiA64 = signUI64; - goto copyA; - } - expA += softfloat_normExtF80SigM( &rem64 ); - } - if ( signUI64 ) goto invalid; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFF; - expA &= 1; - softfloat_shortShiftLeft64To96M( rem64, 30 - expA, rem96 ); - sig32A = rem64>>32; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint64_t) sig32A * recipSqrt32)>>32; - if ( expA ) sig32Z >>= 1; - rem64 = - ((uint64_t) rem96[indexWord( 3, 2 )]<<32 | rem96[indexWord( 3, 1 )]) - - (uint64_t) sig32Z * sig32Z; - rem96[indexWord( 3, 2 )] = rem64>>32; - rem96[indexWord( 3, 1 )] = rem64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - sig64Z = ((uint64_t) sig32Z<<32) + ((uint64_t) q<<3); - term[indexWord( 3, 2 )] = 0; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = ((uint64_t) sig32Z<<32) + sig64Z; - term[indexWord( 3, 1 )] = x64>>32; - term[indexWord( 3, 0 )] = x64; - softfloat_remStep96MBy32( - rem96, 29, term, q, &rem[indexMultiwordHi( 4, 3 )] ); - rem32 = rem[indexWord( 4, 3 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - sig64Z -= 1<<3; - } - rem64 = (uint64_t) rem32<<32 | rem[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32) + 2; - if ( rem64>>34 ) q += recipSqrt32; - x64 = (uint64_t) q<<7; - extSigZ[indexWord( 3, 0 )] = x64; - x64 = (sig64Z<<1) + (x64>>32); - extSigZ[indexWord( 3, 2 )] = x64>>32; - extSigZ[indexWord( 3, 1 )] = x64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xFFFFFF) <= 2 ) { - q &= ~(uint32_t) 0xFFFF; - extSigZ[indexWordLo( 3 )] = q<<7; - x64 = sig64Z + (q>>27); - term[indexWord( 4, 3 )] = 0; - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - term[indexWord( 4, 0 )] = q<<5; - rem[indexWord( 4, 0 )] = 0; - softfloat_remStep128MBy32( rem, 28, term, q, rem ); - q = rem[indexWordHi( 4 )]; - if ( q & 0x80000000 ) { - softfloat_sub1X96M( extSigZ ); - } else { - if ( q || rem[indexWord( 4, 1 )] || rem[indexWord( 4, 2 )] ) { - extSigZ[indexWordLo( 3 )] |= 1; - } - } - } - softfloat_roundPackMToExtF80M( - 0, expZ, extSigZ, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zSPtr->signExp = uiA64; - zSPtr->signif = rem64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_sub.c b/deps/SoftFloat-3e/source/extF80M_sub.c deleted file mode 100644 index 5d1895c7a028..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_sub.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_sub( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - signA = signExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsExtF80 : softfloat_addMagsExtF80; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - extF80M_sub( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - softfloat_addExtF80M( - (const struct extFloat80M *) aPtr, - (const struct extFloat80M *) bPtr, - (struct extFloat80M *) zPtr, - true - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f128M.c b/deps/SoftFloat-3e/source/extF80M_to_f128M.c deleted file mode 100644 index da81e8d6b326..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f128M.c +++ /dev/null @@ -1,125 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) -{ - - *zPtr = extF80_to_f128( *aPtr ); - -} - -#else - -void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) -{ - const struct extFloat80M *aSPtr; - uint32_t *zWPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint32_t uiZ96; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 0 )] = 0; - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) --exp; - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 1 )] = (uint32_t) sig<<17; - sig >>= 15; - zWPtr[indexWord( 4, 2 )] = sig; - if ( exp < 0 ) { - zWPtr[indexWordHi( 4 )] = sig>>32; - softfloat_shiftRight96M( - &zWPtr[indexMultiwordHi( 4, 3 )], - -exp, - &zWPtr[indexMultiwordHi( 4, 3 )] - ); - exp = 0; - sig = (uint64_t) zWPtr[indexWordHi( 4 )]<<32; - } - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp, sig>>32 ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f16.c b/deps/SoftFloat-3e/source/extF80M_to_f16.c deleted file mode 100644 index 5ae38d0c4b8a..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f16.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float16_t extF80M_to_f16( const extFloat80_t *aPtr ) -{ - - return extF80_to_f16( *aPtr ); - -} - -#else - -float16_t extF80M_to_f16( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint16_t uiZ, sig16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig16 = softfloat_shortShiftRightJam64( sig, 49 ); - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, sig16 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f32.c b/deps/SoftFloat-3e/source/extF80M_to_f32.c deleted file mode 100644 index 47cf224dc1f8..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f32.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float32_t extF80M_to_f32( const extFloat80_t *aPtr ) -{ - - return extF80_to_f32( *aPtr ); - -} - -#else - -float32_t extF80M_to_f32( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint32_t uiZ, sig32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = softfloat_shortShiftRightJam64( sig, 33 ); - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, sig32 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f64.c b/deps/SoftFloat-3e/source/extF80M_to_f64.c deleted file mode 100644 index 5f8f4aa2998b..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f64.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t extF80M_to_f64( const extFloat80_t *aPtr ) -{ - - return extF80_to_f64( *aPtr ); - -} - -#else - -float64_t extF80M_to_f64( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = softfloat_shortShiftRightJam64( sig, 1 ); - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF64( sign, exp, sig ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i32.c b/deps/SoftFloat-3e/source/extF80M_to_i32.c deleted file mode 100644 index 06394e34181f..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i32.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t - extF80M_to_i32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_i32( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast32_t - extF80M_to_i32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) { - if ( sig>>32 ) goto invalid; - if ( -32 < shiftDist ) { - sig <<= -shiftDist; - } else { - if ( (uint32_t) sig ) goto invalid; - } - } else { - sig = softfloat_shiftRightJam64( sig, shiftDist ); - } - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c deleted file mode 100644 index 5f5cf599df94..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_i32_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign, raiseInexact; - int32_t z; - uint64_t shiftedSig; - uint32_t absZ; - union { uint32_t ui; int32_t i; } u; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - raiseInexact = exact; - z = 0; - } else { - sign = signExtF80UI64( uiA64 ); - raiseInexact = false; - if ( shiftDist < 0 ) { - if ( sig>>32 || (shiftDist <= -31) ) goto invalid; - shiftedSig = (uint64_t) (uint32_t) sig<<-shiftDist; - if ( shiftedSig>>32 ) goto invalid; - absZ = shiftedSig; - } else { - shiftedSig = sig; - if ( shiftDist ) shiftedSig >>= shiftDist; - if ( shiftedSig>>32 ) goto invalid; - absZ = shiftedSig; - if ( exact && shiftDist ) { - raiseInexact = ((uint64_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t - extF80M_to_i64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_i64( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast64_t - extF80M_to_i64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - uint32_t extSig[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c deleted file mode 100644 index ec9b92844c97..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c +++ /dev/null @@ -1,115 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_i64_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign, raiseInexact; - int64_t z; - uint64_t absZ; - union { uint64_t ui; int64_t i; } u; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - raiseInexact = exact; - z = 0; - } else { - sign = signExtF80UI64( uiA64 ); - raiseInexact = false; - if ( shiftDist < 0 ) { - if ( shiftDist <= -63 ) goto invalid; - shiftDist = -shiftDist; - absZ = sig<>shiftDist != sig ) goto invalid; - } else { - absZ = sig; - if ( shiftDist ) absZ >>= shiftDist; - if ( exact && shiftDist ) raiseInexact = (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t - extF80M_to_ui32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_ui32( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast32_t - extF80M_to_ui32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) { - if ( sig>>32 ) goto invalid; - if ( -32 < shiftDist ) { - sig <<= -shiftDist; - } else { - if ( (uint32_t) sig ) goto invalid; - } - } else { - sig = softfloat_shiftRightJam64( sig, shiftDist ); - } - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c deleted file mode 100644 index e28b08d70d2a..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_ui32_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign; - uint64_t shiftedSig; - uint32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 0 ) { - if ( sign || sig>>32 || (shiftDist <= -31) ) goto invalid; - shiftedSig = (uint64_t) (uint32_t) sig<<-shiftDist; - if ( shiftedSig>>32 ) goto invalid; - z = shiftedSig; - } else { - shiftedSig = sig; - if ( shiftDist ) shiftedSig >>= shiftDist; - if ( shiftedSig>>32 ) goto invalid; - z = shiftedSig; - if ( sign && z ) goto invalid; - if ( exact && shiftDist && ((uint64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t - extF80M_to_ui64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_ui64( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast64_t - extF80M_to_ui64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - uint32_t extSig[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c deleted file mode 100644 index 87d80897b782..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c +++ /dev/null @@ -1,108 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_ui64_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign; - uint64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 0 ) { - if ( sign || (shiftDist <= -63) ) goto invalid; - shiftDist = -shiftDist; - z = sig<>shiftDist != sig ) goto invalid; - } else { - z = sig; - if ( shiftDist ) z >>= shiftDist; - if ( sign && z ) goto invalid; - if ( exact && shiftDist && (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t extF80_add( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsExtF80 : softfloat_subMagsExtF80; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/extF80_div.c b/deps/SoftFloat-3e/source/extF80_div.c deleted file mode 100644 index 28dfb13de8e2..000000000000 --- a/deps/SoftFloat-3e/source/extF80_div.c +++ /dev/null @@ -1,203 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_div( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; - int_fast32_t expB; - uint_fast64_t sigB; - bool signZ; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint128 rem; - uint_fast32_t recip32; - uint_fast64_t sigZ; - int ix; - uint_fast64_t q64; - uint_fast32_t q; - struct uint128 term; - uint_fast64_t sigZExtra; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) { - if ( ! sigA ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFF; - if ( sigA < sigB ) { - --expZ; - rem = softfloat_shortShiftLeft128( 0, sigA, 32 ); - } else { - rem = softfloat_shortShiftLeft128( 0, sigA, 31 ); - } - recip32 = softfloat_approxRecip32_1( sigB>>32 ); - sigZ = 0; - ix = 2; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>2) * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB>>32, sigB<<32 ); - } - sigZ = (sigZ<<29) + q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 0x3FFFFF) < 2 ) { - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - term = softfloat_shortShiftLeft128( 0, sigB, 32 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, term.v64, term.v0 ); - } else if ( softfloat_le128( term.v64, term.v0, rem.v64, rem.v0 ) ) { - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - } - if ( rem.v64 | rem.v0 ) q |= 1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ = (sigZ<<6) + (q>>23); - sigZExtra = (uint64_t) ((uint_fast64_t) q<<41); - return - softfloat_roundPackToExtF80( - signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_eq.c b/deps/SoftFloat-3e/source/extF80_eq.c deleted file mode 100644 index efcbc37143c5..000000000000 --- a/deps/SoftFloat-3e/source/extF80_eq.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_eq( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return - (uiA0 == uiB0) - && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_eq_signaling.c b/deps/SoftFloat-3e/source/extF80_eq_signaling.c deleted file mode 100644 index 193b191e6cf8..000000000000 --- a/deps/SoftFloat-3e/source/extF80_eq_signaling.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool extF80_eq_signaling( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return - (uiA0 == uiB0) - && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c b/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c deleted file mode 100644 index 33d2abd7e9bf..000000000000 --- a/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_isSignalingNaN( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - - uA.f = a; - return softfloat_isSigNaNExtF80UI( uA.s.signExp, uA.s.signif ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_le.c b/deps/SoftFloat-3e/source/extF80_le.c deleted file mode 100644 index 4e23c5142007..000000000000 --- a/deps/SoftFloat-3e/source/extF80_le.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_le( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA || ! (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_le_quiet.c b/deps/SoftFloat-3e/source/extF80_le_quiet.c deleted file mode 100644 index 9839e47f9e01..000000000000 --- a/deps/SoftFloat-3e/source/extF80_le_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_le_quiet( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA || ! (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_lt.c b/deps/SoftFloat-3e/source/extF80_lt.c deleted file mode 100644 index a4ac69fa6c23..000000000000 --- a/deps/SoftFloat-3e/source/extF80_lt.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_lt( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA && (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_lt_quiet.c b/deps/SoftFloat-3e/source/extF80_lt_quiet.c deleted file mode 100644 index 00f4d4768771..000000000000 --- a/deps/SoftFloat-3e/source/extF80_lt_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_lt_quiet( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA && (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_mul.c b/deps/SoftFloat-3e/source/extF80_mul.c deleted file mode 100644 index 39ce4012c454..000000000000 --- a/deps/SoftFloat-3e/source/extF80_mul.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; - int_fast32_t expB; - uint_fast64_t sigB; - bool signZ; - uint_fast64_t magBits; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint128 sig128Z, uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ) { - goto propagateNaN; - } - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - sig128Z = softfloat_mul64To128( sigA, sigB ); - if ( sig128Z.v64 < UINT64_C( 0x8000000000000000 ) ) { - --expZ; - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); - } - return - softfloat_roundPackToExtF80( - signZ, expZ, sig128Z.v64, sig128Z.v0, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - } else { - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_rem.c b/deps/SoftFloat-3e/source/extF80_rem.c deleted file mode 100644 index 5ad977526241..000000000000 --- a/deps/SoftFloat-3e/source/extF80_rem.c +++ /dev/null @@ -1,225 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_rem( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - int_fast32_t expB; - uint_fast64_t sigB; - struct exp32_sig64 normExpSig; - int_fast32_t expDiff; - struct uint128 rem, shiftedSigB; - uint_fast32_t q, recip32; - uint_fast64_t q64; - struct uint128 term, altRem, meanRem; - bool signRem; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ) { - goto propagateNaN; - } - goto invalid; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - /*-------------------------------------------------------------------- - | Argument b is an infinity. Doubling `expB' is an easy way to ensure - | that `expDiff' later is less than -1, which will result in returning - | a canonicalized version of argument a. - *--------------------------------------------------------------------*/ - expB += expB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) { - expA = 0; - goto copyA; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < -1 ) goto copyA; - rem = softfloat_shortShiftLeft128( 0, sigA, 32 ); - shiftedSigB = softfloat_shortShiftLeft128( 0, sigB, 32 ); - if ( expDiff < 1 ) { - if ( expDiff ) { - --expB; - shiftedSigB = softfloat_shortShiftLeft128( 0, sigB, 33 ); - q = 0; - } else { - q = (sigB <= sigA); - if ( q ) { - rem = - softfloat_sub128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } - } - } else { - recip32 = softfloat_approxRecip32_1( sigB>>32 ); - expDiff -= 30; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>2) * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - rem = - softfloat_add128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, expDiff + 30 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - altRem = - softfloat_add128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem = - softfloat_sub128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } while ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = softfloat_add128( rem.v64, rem.v0, altRem.v64, altRem.v0 ); - if ( - (meanRem.v64 & UINT64_C( 0x8000000000000000 )) - || (! (meanRem.v64 | meanRem.v0) && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = softfloat_sub128( 0, 0, rem.v64, rem.v0 ); - } - return - softfloat_normRoundPackToExtF80( - signRem, rem.v64 | rem.v0 ? expB + 32 : 0, rem.v64, rem.v0, 80 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - if ( expA < 1 ) { - sigA >>= 1 - expA; - expA = 0; - } - uiZ64 = packToExtF80UI64( signA, expA ); - uiZ0 = sigA; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_roundToInt.c b/deps/SoftFloat-3e/source/extF80_roundToInt.c deleted file mode 100644 index 6c12d84c9e9f..000000000000 --- a/deps/SoftFloat-3e/source/extF80_roundToInt.c +++ /dev/null @@ -1,154 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - extF80_roundToInt( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64, signUI64; - int_fast32_t exp; - uint_fast64_t sigA; - uint_fast16_t uiZ64; - uint_fast64_t sigZ; - struct exp32_sig64 normExpSig; - struct uint128 uiZ; - uint_fast64_t lastBitMask, roundBitsMask; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - exp = expExtF80UI64( uiA64 ); - sigA = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( !(sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { - if ( !sigA ) { - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - exp += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x403E <= exp ) { - if ( exp == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - uiZ = softfloat_propagateNaNExtF80UI( uiA64, sigA, 0, 0 ); - uiZ64 = uiZ.v64; - sigZ = uiZ.v0; - goto uiZ; - } - sigZ = UINT64_C( 0x8000000000000000 ); - } else { - sigZ = sigA; - } - uiZ64 = signUI64 | exp; - goto uiZ; - } - if ( exp <= 0x3FFE ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( signUI64 ) goto mag1; - break; - case softfloat_round_max: - if ( !signUI64 ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - mag1: - uiZ64 = signUI64 | 0x3FFF; - sigZ = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = signUI64 | exp; - lastBitMask = (uint_fast64_t) 1<<(0x403E - exp); - roundBitsMask = lastBitMask - 1; - sigZ = sigA; - if ( roundingMode == softfloat_round_near_maxMag ) { - sigZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - sigZ += lastBitMask>>1; - if ( !(sigZ & roundBitsMask) ) sigZ &= ~lastBitMask; - } else if ( - roundingMode == (signUI64 ? softfloat_round_min : softfloat_round_max) - ) { - sigZ += roundBitsMask; - } - sigZ &= ~roundBitsMask; - if ( !sigZ ) { - ++uiZ64; - sigZ = UINT64_C( 0x8000000000000000 ); - } - if ( sigZ != sigA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sigZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = sigZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_sqrt.c b/deps/SoftFloat-3e/source/extF80_sqrt.c deleted file mode 100644 index af8c496e1432..000000000000 --- a/deps/SoftFloat-3e/source/extF80_sqrt.c +++ /dev/null @@ -1,176 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_sqrt( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - uint_fast32_t sig32A, recipSqrt32, sig32Z; - struct uint128 rem; - uint_fast64_t q, x64, sigZ; - struct uint128 y, term; - uint_fast64_t sigZExtra; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, 0, 0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! sigA ) goto zero; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFF; - expA &= 1; - sig32A = sigA>>32; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sig32Z >>= 1; - rem = softfloat_shortShiftLeft128( 0, sigA, 61 ); - } else { - rem = softfloat_shortShiftLeft128( 0, sigA, 62 ); - } - rem.v64 -= (uint_fast64_t) sig32Z * sig32Z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem.v64>>2) * (uint_fast64_t) recipSqrt32)>>32; - x64 = (uint_fast64_t) sig32Z<<32; - sigZ = x64 + (q<<3); - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_mul64ByShifted32To128( x64 + sigZ, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - sigZ -= 1<<3; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((rem.v64>>2) * recipSqrt32)>>32) + 2; - x64 = sigZ; - sigZ = (sigZ<<1) + (q>>25); - sigZExtra = (uint64_t) (q<<39); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xFFFFFF) <= 2 ) { - q &= ~(uint_fast64_t) 0xFFFF; - sigZExtra = (uint64_t) (q<<39); - term = softfloat_mul64ByShifted32To128( x64 + (q>>27), q ); - x64 = (uint32_t) (q<<5) * (uint_fast64_t) (uint32_t) q; - term = softfloat_add128( term.v64, term.v0, 0, x64 ); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 28 ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - if ( ! sigZExtra ) --sigZ; - --sigZExtra; - } else { - if ( rem.v64 | rem.v0 ) sigZExtra |= 1; - } - } - return - softfloat_roundPackToExtF80( - 0, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signA, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_sub.c b/deps/SoftFloat-3e/source/extF80_sub.c deleted file mode 100644 index 770c7563a248..000000000000 --- a/deps/SoftFloat-3e/source/extF80_sub.c +++ /dev/null @@ -1,80 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t extF80_sub( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsExtF80 : softfloat_addMagsExtF80; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f128.c b/deps/SoftFloat-3e/source/extF80_to_f128.c deleted file mode 100644 index 4de90ae3166a..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f128.c +++ /dev/null @@ -1,75 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t extF80_to_f128( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - uint_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - bool sign; - struct uint128 frac128; - union ui128_f128 uZ; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - exp = expExtF80UI64( uiA64 ); - frac = uiA0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( (exp == 0x7FFF) && frac ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - sign = signExtF80UI64( uiA64 ); - frac128 = softfloat_shortShiftLeft128( 0, frac, 49 ); - uiZ.v64 = packToF128UI64( sign, exp, frac128.v64 ); - uiZ.v0 = frac128.v0; - } - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f16.c b/deps/SoftFloat-3e/source/extF80_to_f16.c deleted file mode 100644 index 5919403fb9c4..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f16.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t extF80_to_f16( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast16_t uiZ, sig16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig16 = softfloat_shortShiftRightJam64( sig, 49 ); - if ( ! (exp | sig16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, sig16 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f32.c b/deps/SoftFloat-3e/source/extF80_to_f32.c deleted file mode 100644 index 77fcfdc112ec..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f32.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t extF80_to_f32( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast32_t uiZ, sig32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = softfloat_shortShiftRightJam64( sig, 33 ); - if ( ! (exp | sig32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, sig32 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f64.c b/deps/SoftFloat-3e/source/extF80_to_f64.c deleted file mode 100644 index 410d6622c4f0..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f64.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t extF80_to_f64( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (exp | sig) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = softfloat_shortShiftRightJam64( sig, 1 ); - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF64( sign, exp, sig ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i32.c b/deps/SoftFloat-3e/source/extF80_to_i32.c deleted file mode 100644 index 9acdc3c9bc73..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i32.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t - extF80_to_i32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) shiftDist = 1; - sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c deleted file mode 100644 index 03224678a183..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t extF80_to_i32_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 33 ) { - if ( - (uiA64 == packToExtF80UI64( 1, 0x401E )) - && (sig < UINT64_C( 0x8000000100000000 )) - ) { - if ( exact && (sig & UINT64_C( 0x00000000FFFFFFFF )) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - absZ = sig>>shiftDist; - if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - extF80_to_i64( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - uint_fast64_t sigExtra; - struct uint64_extra sig64Extra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigExtra = 0; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64Extra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - } - return softfloat_roundToI64( sign, sig, sigExtra, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c deleted file mode 100644 index 8871d01d107e..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c +++ /dev/null @@ -1,94 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t extF80_to_i64_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist <= 0 ) { - if ( - (uiA64 == packToExtF80UI64( 1, 0x403E )) - && (sig == UINT64_C( 0x8000000000000000 )) - ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - absZ = sig>>shiftDist; - if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sign ? -absZ : absZ; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui32.c b/deps/SoftFloat-3e/source/extF80_to_ui32.c deleted file mode 100644 index 581297731d7c..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui32.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - extF80_to_ui32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) shiftDist = 1; - sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c deleted file mode 100644 index be2c53b1d20d..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( sign || (shiftDist < 32) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - z = sig>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - extF80_to_ui64( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - uint_fast64_t sigExtra; - struct uint64_extra sig64Extra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigExtra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - } - return softfloat_roundToUI64( sign, sig, sigExtra, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c deleted file mode 100644 index eca688c65236..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - z = sig>>shiftDist; - if ( exact && (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_add( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint64_t *aWPtr, *bWPtr; - uint_fast64_t uiA64, uiA0; - bool signA; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - signA = signF128UI64( uiA64 ); - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF128 : softfloat_subMagsF128; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - f128M_add( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - softfloat_addF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (uint32_t *) zPtr, - false - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_div.c b/deps/SoftFloat-3e/source/f128M_div.c deleted file mode 100644 index b443548f5286..000000000000 --- a/deps/SoftFloat-3e/source/f128M_div.c +++ /dev/null @@ -1,187 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_div( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_div( *aPtr, *bPtr ); - -} - -#else - -void - f128M_div( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr, uiA96; - bool signA; - int32_t expA; - uint32_t uiB96; - bool signB; - int32_t expB; - bool signZ; - uint32_t y[5], sigB[4]; - int32_t expZ; - uint32_t recip32; - int ix; - uint64_t q64; - uint32_t q, qs[3], uiZ96; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - signB = signF128UI96( uiB96 ); - expB = expF128UI96( uiB96 ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - if ( expA == 0x7FFF ) { - if ( expB == 0x7FFF ) goto invalid; - goto infinity; - } - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = softfloat_shiftNormSigF128M( aWPtr, 13, y ); - expB = softfloat_shiftNormSigF128M( bWPtr, 13, sigB ); - if ( expA == -128 ) { - if ( expB == -128 ) goto invalid; - goto zero; - } - if ( expB == -128 ) { - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFE; - if ( softfloat_compare128M( y, sigB ) < 0 ) { - --expZ; - softfloat_add128M( y, y, y ); - } - recip32 = - softfloat_approxRecip32_1( - ((uint64_t) sigB[indexWord( 4, 3 )]<<32 | sigB[indexWord( 4, 2 )]) - >>30 - ); - ix = 3; - for (;;) { - q64 = (uint64_t) y[indexWordHi( 4 )] * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - softfloat_remStep128MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 4 )] & 0x80000000 ) { - --q; - softfloat_add128M( y, sigB, y ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 7) < 2 ) { - softfloat_remStep128MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 4 )] & 0x80000000 ) { - --q; - softfloat_add128M( y, sigB, y ); - } else if ( softfloat_compare128M( sigB, y ) <= 0 ) { - ++q; - softfloat_sub128M( y, sigB, y ); - } - if ( - y[indexWordLo( 4 )] || y[indexWord( 4, 1 )] - || (y[indexWord( 4, 2 )] | y[indexWord( 4, 3 )]) - ) { - q |= 1; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q64 = (uint64_t) q<<28; - y[indexWord( 5, 0 )] = q64; - q64 = ((uint64_t) qs[0]<<25) + (q64>>32); - y[indexWord( 5, 1 )] = q64; - q64 = ((uint64_t) qs[1]<<22) + (q64>>32); - y[indexWord( 5, 2 )] = q64; - q64 = ((uint64_t) qs[2]<<19) + (q64>>32); - y[indexWord( 5, 3 )] = q64; - y[indexWord( 5, 4 )] = q64>>32; - softfloat_roundPackMToF128M( signZ, expZ, y, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ96 = packToF128UI96( signZ, 0x7FFF, 0 ); - goto uiZ96; - zero: - uiZ96 = packToF128UI96( signZ, 0, 0 ); - uiZ96: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_eq.c b/deps/SoftFloat-3e/source/f128M_eq.c deleted file mode 100644 index 497fdbf6f037..000000000000 --- a/deps/SoftFloat-3e/source/f128M_eq.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_eq( *aPtr, *bPtr ); - -} - -#else - -bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t wordA, wordB, uiA96, uiB96; - bool possibleOppositeZeros; - uint32_t mashWord; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - possibleOppositeZeros = false; - if ( uiA96 != uiB96 ) { - possibleOppositeZeros = (((uiA96 | uiB96) & 0x7FFFFFFF) == 0); - if ( ! possibleOppositeZeros ) goto false_checkSigNaNs; - } - mashWord = wordA | wordB; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - mashWord |= wordA | wordB; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - if ( possibleOppositeZeros && ((mashWord | wordA | wordB) != 0) ) { - goto false_checkSigNaNs; - } - if ( ! softfloat_isNaNF128M( aWPtr ) && ! softfloat_isNaNF128M( bWPtr ) ) { - return true; - } - false_checkSigNaNs: - if ( - f128M_isSignalingNaN( (const float128_t *) aWPtr ) - || f128M_isSignalingNaN( (const float128_t *) bWPtr ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_eq_signaling.c b/deps/SoftFloat-3e/source/f128M_eq_signaling.c deleted file mode 100644 index a9fa4d5101fb..000000000000 --- a/deps/SoftFloat-3e/source/f128M_eq_signaling.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_eq_signaling( *aPtr, *bPtr ); - -} - -#else - -bool f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t wordA, wordB, uiA96, uiB96; - bool possibleOppositeZeros; - uint32_t mashWord; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA != wordB ) return false; - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - possibleOppositeZeros = false; - if ( uiA96 != uiB96 ) { - possibleOppositeZeros = (((uiA96 | uiB96) & 0x7FFFFFFF) == 0); - if ( ! possibleOppositeZeros ) return false; - } - mashWord = wordA | wordB; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA != wordB ) return false; - mashWord |= wordA | wordB; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return - (wordA == wordB) - && (! possibleOppositeZeros || ((mashWord | wordA | wordB) == 0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_le.c b/deps/SoftFloat-3e/source/f128M_le.c deleted file mode 100644 index 7306e45c363c..000000000000 --- a/deps/SoftFloat-3e/source/f128M_le.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_le( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_le( *aPtr, *bPtr ); - -} - -#else - -bool f128M_le( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signA ) return true; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return false; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) == 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) <= 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_le_quiet.c b/deps/SoftFloat-3e/source/f128M_le_quiet.c deleted file mode 100644 index d9e442942d62..000000000000 --- a/deps/SoftFloat-3e/source/f128M_le_quiet.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_le_quiet( *aPtr, *bPtr ); - -} - -#else - -bool f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - if ( f128M_isSignalingNaN( aPtr ) || f128M_isSignalingNaN( bPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signA ) return true; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return false; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) == 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) <= 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_lt.c b/deps/SoftFloat-3e/source/f128M_lt.c deleted file mode 100644 index d2f797feaff3..000000000000 --- a/deps/SoftFloat-3e/source/f128M_lt.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_lt( *aPtr, *bPtr ); - -} - -#else - -bool f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signB ) return false; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return true; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) != 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) < 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_lt_quiet.c b/deps/SoftFloat-3e/source/f128M_lt_quiet.c deleted file mode 100644 index adbddea71caf..000000000000 --- a/deps/SoftFloat-3e/source/f128M_lt_quiet.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_lt_quiet( *aPtr, *bPtr ); - -} - -#else - -bool f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - if ( f128M_isSignalingNaN( aPtr ) || f128M_isSignalingNaN( bPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signB ) return false; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return true; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) != 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) < 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_mul.c b/deps/SoftFloat-3e/source/f128M_mul.c deleted file mode 100644 index 4b8292a27a72..000000000000 --- a/deps/SoftFloat-3e/source/f128M_mul.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_mul( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_mul( *aPtr, *bPtr ); - -} - -#else - -void - f128M_mul( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr; - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - bool signZ; - const uint32_t *ptr; - uint32_t uiZ96, sigA[4]; - uint_fast8_t shiftDist; - uint32_t sigB[4]; - int32_t expZ; - uint32_t sigProd[8], *extSigZPtr; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - signZ = signF128UI96( uiA96 ) ^ signF128UI96( uiB96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - ptr = aWPtr; - if ( ! expA ) goto possiblyInvalid; - if ( ! expB ) { - ptr = bWPtr; - possiblyInvalid: - if ( - ! fracF128UI96( ptr[indexWordHi( 4 )] ) - && ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )] - | ptr[indexWord( 4, 0 )]) - ) { - softfloat_invalidF128M( zWPtr ); - return; - } - } - uiZ96 = packToF128UI96( signZ, 0x7FFF, 0 ); - goto uiZ96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA ) { - sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000; - sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - } else { - expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA ); - if ( expA == -128 ) goto zero; - } - if ( expB ) { - sigB[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000; - sigB[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )]; - sigB[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )]; - sigB[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )]; - } else { - expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigB ); - if ( expB == -128 ) goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x4000; - softfloat_mul128MTo256M( sigA, sigB, sigProd ); - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigZPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - shiftDist = 16; - if ( extSigZPtr[indexWordHi( 5 )] & 2 ) { - ++expZ; - shiftDist = 15; - } - softfloat_shortShiftLeft160M( extSigZPtr, shiftDist, extSigZPtr ); - softfloat_roundPackMToF128M( signZ, expZ, extSigZPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ96 = packToF128UI96( signZ, 0, 0 ); - uiZ96: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_mulAdd.c b/deps/SoftFloat-3e/source/f128M_mulAdd.c deleted file mode 100644 index 2b0b7fe26e69..000000000000 --- a/deps/SoftFloat-3e/source/f128M_mulAdd.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_mulAdd( - const float128_t *aPtr, - const float128_t *bPtr, - const float128_t *cPtr, - float128_t *zPtr - ) -{ - const uint64_t *aWPtr, *bWPtr, *cWPtr; - uint_fast64_t uiA64, uiA0; - uint_fast64_t uiB64, uiB0; - uint_fast64_t uiC64, uiC0; - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - cWPtr = (const uint64_t *) cPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - uiC64 = cWPtr[indexWord( 2, 1 )]; - uiC0 = cWPtr[indexWord( 2, 0 )]; - *zPtr = softfloat_mulAddF128( uiA64, uiA0, uiB64, uiB0, uiC64, uiC0, 0 ); - -} - -#else - -void - f128M_mulAdd( - const float128_t *aPtr, - const float128_t *bPtr, - const float128_t *cPtr, - float128_t *zPtr - ) -{ - - softfloat_mulAddF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (const uint32_t *) cPtr, - (uint32_t *) zPtr, - 0 - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_rem.c b/deps/SoftFloat-3e/source/f128M_rem.c deleted file mode 100644 index 39aafdd6ad5c..000000000000 --- a/deps/SoftFloat-3e/source/f128M_rem.c +++ /dev/null @@ -1,182 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_rem( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_rem( *aPtr, *bPtr ); - -} - -#else - -void - f128M_rem( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr, uiA96; - int32_t expA, expB; - uint32_t x[4], rem1[5], *remPtr; - bool signRem; - int32_t expDiff; - uint32_t q, recip32; - uint64_t q64; - uint32_t rem2[5], *altRemPtr, *newRemPtr, wordMeanRem; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - expB = expF128UI96( bWPtr[indexWordHi( 4 )] ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - if ( expA == 0x7FFF ) goto invalid; - goto copyA; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA < expB - 1 ) goto copyA; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expB = softfloat_shiftNormSigF128M( bWPtr, 13, x ); - if ( expB == -128 ) goto invalid; - remPtr = &rem1[indexMultiwordLo( 5, 4 )]; - expA = softfloat_shiftNormSigF128M( aWPtr, 13, remPtr ); - if ( expA == -128 ) goto copyA; - signRem = signF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) goto copyA; - if ( expDiff ) { - --expB; - softfloat_add128M( x, x, x ); - q = 0; - } else { - q = (softfloat_compare128M( x, remPtr ) <= 0); - if ( q ) softfloat_sub128M( remPtr, x, remPtr ); - } - } else { - recip32 = - softfloat_approxRecip32_1( - ((uint64_t) x[indexWord( 4, 3 )]<<32 | x[indexWord( 4, 2 )]) - >>30 - ); - expDiff -= 30; - for (;;) { - q64 = (uint64_t) remPtr[indexWordHi( 4 )] * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - softfloat_remStep128MBy32( remPtr, 29, x, q, remPtr ); - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - softfloat_add128M( remPtr, x, remPtr ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - softfloat_remStep128MBy32( remPtr, expDiff + 30, x, q, remPtr ); - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - altRemPtr = &rem2[indexMultiwordLo( 5, 4 )]; - softfloat_add128M( remPtr, x, altRemPtr ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - altRemPtr = &rem2[indexMultiwordLo( 5, 4 )]; - do { - ++q; - newRemPtr = altRemPtr; - softfloat_sub128M( remPtr, x, newRemPtr ); - altRemPtr = remPtr; - remPtr = newRemPtr; - } while ( ! (remPtr[indexWordHi( 4 )] & 0x80000000) ); - selectRem: - softfloat_add128M( remPtr, altRemPtr, x ); - wordMeanRem = x[indexWordHi( 4 )]; - if ( - (wordMeanRem & 0x80000000) - || (! wordMeanRem && (q & 1) && ! x[indexWord( 4, 0 )] - && ! (x[indexWord( 4, 2 )] | x[indexWord( 4, 1 )])) - ) { - remPtr = altRemPtr; - } - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - signRem = ! signRem; - softfloat_negX128M( remPtr ); - } - remPtr -= indexMultiwordLo( 5, 4 ); - remPtr[indexWordHi( 5 )] = 0; - softfloat_normRoundPackMToF128M( signRem, expB + 18, remPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zWPtr[indexWordHi( 4 )] = uiA96; - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_roundToInt.c b/deps/SoftFloat-3e/source/f128M_roundToInt.c deleted file mode 100644 index b96d742b214b..000000000000 --- a/deps/SoftFloat-3e/source/f128M_roundToInt.c +++ /dev/null @@ -1,223 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_roundToInt( - const float128_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - float128_t *zPtr - ) -{ - - *zPtr = f128_roundToInt( *aPtr, roundingMode, exact ); - -} - -#else - -void - f128M_roundToInt( - const float128_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - float128_t *zPtr - ) -{ - const uint32_t *aWPtr; - uint32_t *zWPtr; - uint32_t ui96; - int32_t exp; - uint32_t sigExtra; - bool sign; - uint_fast8_t bitPos; - bool roundNear; - unsigned int index, lastIndex; - bool extra; - uint32_t wordA, bit, wordZ; - uint_fast8_t carry; - uint32_t extrasMask; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ui96 = aWPtr[indexWordHi( 4 )]; - exp = expF128UI96( ui96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - sigExtra = aWPtr[indexWord( 4, 2 )]; - if ( !sigExtra ) { - sigExtra = aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]; - } - if ( !sigExtra && !(ui96 & 0x7FFFFFFF) ) goto ui96; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - sign = signF128UI96( ui96 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF128UI96( ui96 ) && !sigExtra ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( sign ) goto mag1; - break; - case softfloat_round_max: - if ( !sign ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - ui96 = packToF128UI96( sign, 0, 0 ); - goto ui96; - mag1: - ui96 = packToF128UI96( sign, 0x3FFF, 0 ); - goto ui96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x406F <= exp ) { - if ( - (exp == 0x7FFF) - && (fracF128UI96( ui96 ) - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ) { - softfloat_propagateNaNF128M( aWPtr, 0, zWPtr ); - return; - } - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - goto ui96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - bitPos = 0x406F - exp; - roundNear = - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even); - bitPos -= roundNear; - index = indexWordLo( 4 ); - lastIndex = indexWordHi( 4 ); - extra = 0; - for (;;) { - wordA = aWPtr[index]; - if ( bitPos < 32 ) break; - if ( wordA ) extra = 1; - zWPtr[index] = 0; - index += wordIncr; - bitPos -= 32; - } - bit = (uint32_t) 1< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) -{ - - *zPtr = f128_sqrt( *aPtr ); - -} - -#else - -void f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr; - uint32_t *zWPtr; - uint32_t uiA96; - bool signA; - int32_t rawExpA; - uint32_t rem[6]; - int32_t expA, expZ; - uint64_t rem64; - uint32_t sig32A, recipSqrt32, sig32Z, qs[3], q; - uint64_t sig64Z; - uint32_t term[5]; - uint64_t x64; - uint32_t y[5], rem32; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - rawExpA = expF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( rawExpA == 0x7FFF ) { - if ( - fracF128UI96( uiA96 ) - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - ) { - softfloat_propagateNaNF128M( aWPtr, 0, zWPtr ); - return; - } - if ( ! signA ) goto copyA; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = softfloat_shiftNormSigF128M( aWPtr, 13 - (rawExpA & 1), rem ); - if ( expA == -128 ) goto copyA; - if ( signA ) goto invalid; - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFE; - expA &= 1; - rem64 = (uint64_t) rem[indexWord( 4, 3 )]<<32 | rem[indexWord( 4, 2 )]; - if ( expA ) { - if ( ! rawExpA ) { - softfloat_shortShiftRight128M( rem, 1, rem ); - rem64 >>= 1; - } - sig32A = rem64>>29; - } else { - sig32A = rem64>>30; - } - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint64_t) sig32A * recipSqrt32)>>32; - if ( expA ) sig32Z >>= 1; - qs[2] = sig32Z; - rem64 -= (uint64_t) sig32Z * sig32Z; - rem[indexWord( 4, 3 )] = rem64>>32; - rem[indexWord( 4, 2 )] = rem64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - sig64Z = ((uint64_t) sig32Z<<32) + ((uint64_t) q<<3); - term[indexWord( 4, 3 )] = 0; - term[indexWord( 4, 0 )] = 0; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = ((uint64_t) sig32Z<<32) + sig64Z; - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - softfloat_remStep128MBy32( rem, 29, term, q, y ); - rem32 = y[indexWord( 4, 3 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - sig64Z -= 1<<3; - } - qs[1] = q; - rem64 = (uint64_t) rem32<<32 | y[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - if ( rem64>>34 ) q += recipSqrt32; - sig64Z <<= 1; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = sig64Z + (q>>26); - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - term[indexWord( 4, 0 )] = q<<6; - softfloat_remStep128MBy32( - y, 29, term, q, &rem[indexMultiwordHi( 6, 4 )] ); - rem32 = rem[indexWordHi( 6 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - } - qs[0] = q; - rem64 = (uint64_t) rem32<<32 | rem[indexWord( 6, 4 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32) + 2; - if ( rem64>>34 ) q += recipSqrt32; - x64 = (uint64_t) q<<27; - y[indexWord( 5, 0 )] = x64; - x64 = ((uint64_t) qs[0]<<24) + (x64>>32); - y[indexWord( 5, 1 )] = x64; - x64 = ((uint64_t) qs[1]<<21) + (x64>>32); - y[indexWord( 5, 2 )] = x64; - x64 = ((uint64_t) qs[2]<<18) + (x64>>32); - y[indexWord( 5, 3 )] = x64; - y[indexWord( 5, 4 )] = x64>>32; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xF) <= 2 ) { - q &= ~3; - y[indexWordLo( 5 )] = q<<27; - term[indexWord( 5, 4 )] = 0; - term[indexWord( 5, 3 )] = 0; - term[indexWord( 5, 2 )] = 0; - term[indexWord( 5, 1 )] = q>>6; - term[indexWord( 5, 0 )] = q<<26; - softfloat_sub160M( y, term, term ); - rem[indexWord( 6, 1 )] = 0; - rem[indexWord( 6, 0 )] = 0; - softfloat_remStep160MBy32( - &rem[indexMultiwordLo( 6, 5 )], - 14, - term, - q, - &rem[indexMultiwordLo( 6, 5 )] - ); - rem32 = rem[indexWord( 6, 4 )]; - if ( rem32 & 0x80000000 ) { - softfloat_sub1X160M( y ); - } else { - if ( - rem32 || rem[indexWord( 6, 0 )] || rem[indexWord( 6, 1 )] - || (rem[indexWord( 6, 3 )] | rem[indexWord( 6, 2 )]) - ) { - y[indexWordLo( 5 )] |= 1; - } - } - } - softfloat_roundPackMToF128M( 0, expZ, y, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zWPtr[indexWordHi( 4 )] = uiA96; - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_sub.c b/deps/SoftFloat-3e/source/f128M_sub.c deleted file mode 100644 index 5d65c799f31f..000000000000 --- a/deps/SoftFloat-3e/source/f128M_sub.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_sub( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint64_t *aWPtr, *bWPtr; - uint_fast64_t uiA64, uiA0; - bool signA; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - signA = signF128UI64( uiA64 ); - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF128 : softfloat_addMagsF128; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - f128M_sub( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - softfloat_addF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (uint32_t *) zPtr, - true - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_extF80M.c b/deps/SoftFloat-3e/source/f128M_to_extF80M.c deleted file mode 100644 index b0340c794854..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_extF80M.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) -{ - - *zPtr = f128_to_extF80( *aPtr ); - -} - -#else - -void f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) -{ - const uint32_t *aWPtr; - struct extFloat80M *zSPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - struct commonNaN commonNaN; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( softfloat_isNaNF128M( aWPtr ) ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - zSPtr->signExp = packToExtF80UI64( sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0x8000000000000000 ); - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp = softfloat_shiftNormSigF128M( aWPtr, 15, sig ); - if ( exp == -128 ) { - zSPtr->signExp = packToExtF80UI64( sign, 0 ); - zSPtr->signif = 0; - return; - } - if ( sig[indexWord( 4, 0 )] ) sig[indexWord( 4, 1 )] |= 1; - softfloat_roundPackMToExtF80M( - sign, exp, &sig[indexMultiwordHi( 4, 3 )], 80, zSPtr ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f16.c b/deps/SoftFloat-3e/source/f128M_to_f16.c deleted file mode 100644 index 95109a771d70..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f16.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float16_t f128M_to_f16( const float128_t *aPtr ) -{ - - return f128_to_f16( *aPtr ); - -} - -#else - -float16_t f128M_to_f16( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t frac32; - struct commonNaN commonNaN; - uint16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac32 = - fracF128UI96( uiA96 ) - | ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac32 ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = frac32>>2 | (frac32 & 3); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, frac16 | 0x4000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f32.c b/deps/SoftFloat-3e/source/f128M_to_f32.c deleted file mode 100644 index 4542deb0c384..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f32.c +++ /dev/null @@ -1,109 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float32_t f128M_to_f32( const float128_t *aPtr ) -{ - - return f128_to_f32( *aPtr ); - -} - -#else - -float32_t f128M_to_f32( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t frac64; - struct commonNaN commonNaN; - uint32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac64 = - (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )] - | ((aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]) != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f64.c b/deps/SoftFloat-3e/source/f128M_to_f64.c deleted file mode 100644 index 6213bb7f50a2..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f64.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t f128M_to_f64( const float128_t *aPtr ) -{ - - return f128_to_f64( *aPtr ); - -} - -#else - -float64_t f128M_to_f64( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t frac64; - struct commonNaN commonNaN; - uint64_t uiZ; - uint32_t frac32; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 || aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = aWPtr[indexWord( 4, 1 )]; - frac64 = frac64<<14 | frac32>>18; - if ( (frac32 & 0x0003FFFF) || aWPtr[indexWord( 4, 0 )] ) frac64 |= 1; - if ( ! (exp | frac64) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return - softfloat_roundPackToF64( - sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i32.c b/deps/SoftFloat-3e/source/f128M_to_i32.c deleted file mode 100644 index 54cc6f603737..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t - f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_i32( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast32_t - f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c deleted file mode 100644 index 1f22039dedb3..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_i32_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - uint32_t absZ, uiZ; - union { uint32_t ui; int32_t i; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x401F <= exp ) goto invalid; - shiftDist = 0x402F - exp; - sig64 |= UINT64_C( 0x0001000000000000 ); - absZ = sig64>>shiftDist; - uiZ = sign ? -absZ : absZ; - if ( uiZ>>31 != sign ) goto invalid; - if ( exact && ((uint64_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t - f128M_to_i64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_i64( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast64_t - f128M_to_i64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x404F - exp; - if ( shiftDist < 17 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist, sig ); - return - softfloat_roundMToI64( - sign, sig + indexMultiwordLo( 4, 3 ), roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c deleted file mode 100644 index da3d28ad0b93..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c +++ /dev/null @@ -1,124 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_i64_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast64_t f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - uint64_t uiZ; - union { uint64_t ui; int64_t i; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) goto invalid; - if ( exact ) { - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist + 17, sig ); - uiZ = (uint64_t) sig[indexWord( 4, 2 )]<<32 | sig[indexWord( 4, 1 )]; - if ( uiZ>>63 && (! sign || (uiZ != UINT64_C( 0x8000000000000000 ))) ) { - goto invalid; - } - if ( sig[indexWordLo( 4 )] ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } else { - if ( 64 <= shiftDist ) return 0; - uiZ = - (uint64_t) sig96<<47 - | (uint64_t) aWPtr[indexWord( 4, 2 )]<<15 - | aWPtr[indexWord( 4, 1 )]>>17; - if ( shiftDist ) { - uiZ |= UINT64_C( 0x8000000000000000 ); - uiZ >>= shiftDist; - } else { - if ( uiZ || ! sign ) goto invalid; - uiZ |= UINT64_C( 0x8000000000000000 ); - } - } - if ( sign ) uiZ = -uiZ; - uZ.ui = uiZ; - return uZ.i; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui32.c b/deps/SoftFloat-3e/source/f128M_to_ui32.c deleted file mode 100644 index c1baa063a6dc..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t - f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_ui32( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast32_t - f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c deleted file mode 100644 index a1aca621ab38..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c +++ /dev/null @@ -1,102 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_ui32_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - bool sign; - uint32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI96( uiA96 ); - if ( sign || (shiftDist < 17) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - z = sig64>>shiftDist; - if ( exact && ((uint64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t - f128M_to_ui64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_ui64( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast64_t - f128M_to_ui64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x404F - exp; - if ( shiftDist < 17 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist, sig ); - return - softfloat_roundMToUI64( - sign, sig + indexMultiwordLo( 4, 3 ), roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c deleted file mode 100644 index 7a1b602959c1..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c +++ /dev/null @@ -1,114 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_ui64_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - uint64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) goto invalid; - if ( exact ) { - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist + 17, sig ); - z = (uint64_t) sig[indexWord( 4, 2 )]<<32 | sig[indexWord( 4, 1 )]; - if ( sign && z ) goto invalid; - if ( sig[indexWordLo( 4 )] ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } else { - if ( 64 <= shiftDist ) return 0; - if ( sign ) goto invalid; - z = UINT64_C( 0x8000000000000000 ) - | (uint64_t) sig96<<47 - | (uint64_t) aWPtr[indexWord( 4, 2 )]<<15 - | aWPtr[indexWord( 4, 1 )]>>17; - z >>= shiftDist; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128_add.c b/deps/SoftFloat-3e/source/f128_add.c deleted file mode 100644 index e9caba682593..000000000000 --- a/deps/SoftFloat-3e/source/f128_add.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_add( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF128 : softfloat_subMagsF128; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f128_div.c b/deps/SoftFloat-3e/source/f128_div.c deleted file mode 100644 index 0693db754a60..000000000000 --- a/deps/SoftFloat-3e/source/f128_div.c +++ /dev/null @@ -1,199 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_div( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - struct uint128 rem; - uint_fast32_t recip32; - int ix; - uint_fast64_t q64; - uint_fast32_t q; - struct uint128 term; - uint_fast32_t qs[3]; - uint_fast64_t sigZExtra; - struct uint128 sigZ, uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) { - if ( ! (expA | sigA.v64 | sigA.v0) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFE; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - rem = sigA; - if ( softfloat_lt128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ) ) { - --expZ; - rem = softfloat_add128( sigA.v64, sigA.v0, sigA.v64, sigA.v0 ); - } - recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); - ix = 3; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 7) < 2 ) { - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } else if ( softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ) ) { - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - if ( rem.v64 | rem.v0 ) q |= 1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZExtra = (uint64_t) ((uint_fast64_t) q<<60); - term = softfloat_shortShiftLeft128( 0, qs[1], 54 ); - sigZ = - softfloat_add128( - (uint_fast64_t) qs[2]<<19, ((uint_fast64_t) qs[0]<<25) + (q>>4), - term.v64, term.v0 - ); - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - goto uiZ0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ.v64 = packToF128UI64( signZ, 0, 0 ); - uiZ0: - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_eq.c b/deps/SoftFloat-3e/source/f128_eq.c deleted file mode 100644 index 9462fc2abd06..000000000000 --- a/deps/SoftFloat-3e/source/f128_eq.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_eq( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return - (uiA0 == uiB0) - && ( (uiA64 == uiB64) - || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_eq_signaling.c b/deps/SoftFloat-3e/source/f128_eq_signaling.c deleted file mode 100644 index 5d0819d291b9..000000000000 --- a/deps/SoftFloat-3e/source/f128_eq_signaling.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_eq_signaling( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return - (uiA0 == uiB0) - && ( (uiA64 == uiB64) - || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_isSignalingNaN.c b/deps/SoftFloat-3e/source/f128_isSignalingNaN.c deleted file mode 100644 index a764ff6bfebc..000000000000 --- a/deps/SoftFloat-3e/source/f128_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_isSignalingNaN( float128_t a ) -{ - union ui128_f128 uA; - - uA.f = a; - return softfloat_isSigNaNF128UI( uA.ui.v64, uA.ui.v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_le.c b/deps/SoftFloat-3e/source/f128_le.c deleted file mode 100644 index 521a1cb03725..000000000000 --- a/deps/SoftFloat-3e/source/f128_le.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_le( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_le_quiet.c b/deps/SoftFloat-3e/source/f128_le_quiet.c deleted file mode 100644 index 820b28b810a1..000000000000 --- a/deps/SoftFloat-3e/source/f128_le_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_le_quiet( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_lt.c b/deps/SoftFloat-3e/source/f128_lt.c deleted file mode 100644 index fa46ae2bce69..000000000000 --- a/deps/SoftFloat-3e/source/f128_lt.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_lt( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_lt_quiet.c b/deps/SoftFloat-3e/source/f128_lt_quiet.c deleted file mode 100644 index d491de2f2d02..000000000000 --- a/deps/SoftFloat-3e/source/f128_lt_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_lt_quiet( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_mul.c b/deps/SoftFloat-3e/source/f128_mul.c deleted file mode 100644 index 24af86a245d2..000000000000 --- a/deps/SoftFloat-3e/source/f128_mul.c +++ /dev/null @@ -1,163 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_mul( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signZ; - uint_fast64_t magBits; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint64_t sig256Z[4]; - uint_fast64_t sigZExtra; - struct uint128 sigZ; - struct uint128_extra sig128Extra; - struct uint128 uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN; - } - magBits = expB | sigB.v64 | sigB.v0; - goto infArg; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - magBits = expA | sigA.v64 | sigA.v0; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x4000; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 16 ); - softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); - sigZExtra = sig256Z[indexWord( 4, 1 )] | (sig256Z[indexWord( 4, 0 )] != 0); - sigZ = - softfloat_add128( - sig256Z[indexWord( 4, 3 )], sig256Z[indexWord( 4, 2 )], - sigA.v64, sigA.v0 - ); - if ( UINT64_C( 0x0002000000000000 ) <= sigZ.v64 ) { - ++expZ; - sig128Extra = - softfloat_shortShiftRightJam128Extra( - sigZ.v64, sigZ.v0, sigZExtra, 1 ); - sigZ = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - } - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - goto uiZ0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ.v64 = packToF128UI64( signZ, 0, 0 ); - uiZ0: - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_mulAdd.c b/deps/SoftFloat-3e/source/f128_mulAdd.c deleted file mode 100644 index c7272d4e0e9f..000000000000 --- a/deps/SoftFloat-3e/source/f128_mulAdd.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_mulAdd( float128_t a, float128_t b, float128_t c ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - union ui128_f128 uC; - uint_fast64_t uiC64, uiC0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - uC.f = c; - uiC64 = uC.ui.v64; - uiC0 = uC.ui.v0; - return softfloat_mulAddF128( uiA64, uiA0, uiB64, uiB0, uiC64, uiC0, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_rem.c b/deps/SoftFloat-3e/source/f128_rem.c deleted file mode 100644 index f525f697a58c..000000000000 --- a/deps/SoftFloat-3e/source/f128_rem.c +++ /dev/null @@ -1,190 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_rem( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - int_fast32_t expB; - struct uint128 sigB; - struct exp32_sig128 normExpSig; - struct uint128 rem; - int_fast32_t expDiff; - uint_fast32_t q, recip32; - uint_fast64_t q64; - struct uint128 term, altRem, meanRem; - bool signRem; - struct uint128 uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN; - } - goto invalid; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto invalid; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) return a; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - rem = sigA; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - if ( expDiff ) { - --expB; - sigB = softfloat_add128( sigB.v64, sigB.v0, sigB.v64, sigB.v0 ); - q = 0; - } else { - q = softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ); - if ( q ) { - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - } - } else { - recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); - expDiff -= 30; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, expDiff + 30 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - altRem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } while ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = softfloat_add128( rem.v64, rem.v0, altRem.v64, altRem.v0 ); - if ( - (meanRem.v64 & UINT64_C( 0x8000000000000000 )) - || (! (meanRem.v64 | meanRem.v0) && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = softfloat_sub128( 0, 0, rem.v64, rem.v0 ); - } - return softfloat_normRoundPackToF128( signRem, expB - 1, rem.v64, rem.v0 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_roundToInt.c b/deps/SoftFloat-3e/source/f128_roundToInt.c deleted file mode 100644 index 69185d6efa69..000000000000 --- a/deps/SoftFloat-3e/source/f128_roundToInt.c +++ /dev/null @@ -1,172 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - f128_roundToInt( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - struct uint128 uiZ; - uint_fast64_t lastBitMask0, roundBitsMask; - bool roundNearEven; - uint_fast64_t lastBitMask64; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x402F <= exp ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( 0x406F <= exp ) { - if ( (exp == 0x7FFF) && (fracF128UI64( uiA64 ) | uiA0) ) { - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); - goto uiZ; - } - return a; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - lastBitMask0 = (uint_fast64_t) 2<<(0x406E - exp); - roundBitsMask = lastBitMask0 - 1; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - roundNearEven = (roundingMode == softfloat_round_near_even); - if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) ) { - if ( exp == 0x402F ) { - if ( UINT64_C( 0x8000000000000000 ) <= uiZ.v0 ) { - ++uiZ.v64; - if ( - roundNearEven - && (uiZ.v0 == UINT64_C( 0x8000000000000000 )) - ) { - uiZ.v64 &= ~1; - } - } - } else { - uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, lastBitMask0>>1 ); - if ( roundNearEven && !(uiZ.v0 & roundBitsMask) ) { - uiZ.v0 &= ~lastBitMask0; - } - } - } else if ( - roundingMode - == (signF128UI64( uiZ.v64 ) ? softfloat_round_min - : softfloat_round_max) - ) { - uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, roundBitsMask ); - } - uiZ.v0 &= ~roundBitsMask; - lastBitMask64 = !lastBitMask0; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - if ( !((uiA64 & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ.v64 = uiA64 & packToF128UI64( 1, 0, 0 ); - uiZ.v0 = 0; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(fracF128UI64( uiA64 ) | uiA0) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) uiZ.v64 |= packToF128UI64( 0, 0x3FFF, 0 ); - break; - case softfloat_round_min: - if ( uiZ.v64 ) uiZ.v64 = packToF128UI64( 1, 0x3FFF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ.v64 ) uiZ.v64 = packToF128UI64( 0, 0x3FFF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ.v64 |= packToF128UI64( 0, 0x3FFF, 0 ); - break; -#endif - } - goto uiZ; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - uiZ.v64 = uiA64; - uiZ.v0 = 0; - lastBitMask64 = (uint_fast64_t) 1<<(0x402F - exp); - roundBitsMask = lastBitMask64 - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ.v64 += lastBitMask64>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ.v64 += lastBitMask64>>1; - if ( !((uiZ.v64 & roundBitsMask) | uiA0) ) { - uiZ.v64 &= ~lastBitMask64; - } - } else if ( - roundingMode - == (signF128UI64( uiZ.v64 ) ? softfloat_round_min - : softfloat_round_max) - ) { - uiZ.v64 = (uiZ.v64 | (uiA0 != 0)) + roundBitsMask; - } - uiZ.v64 &= ~roundBitsMask; - lastBitMask0 = 0; - } - if ( (uiZ.v64 != uiA64) || (uiZ.v0 != uiA0) ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - uiZ.v64 |= lastBitMask64; - uiZ.v0 |= lastBitMask0; - } -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_sqrt.c b/deps/SoftFloat-3e/source/f128_sqrt.c deleted file mode 100644 index f1d9bac79287..000000000000 --- a/deps/SoftFloat-3e/source/f128_sqrt.c +++ /dev/null @@ -1,201 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_sqrt( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA, uiZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint_fast32_t sig32A, recipSqrt32, sig32Z; - struct uint128 rem; - uint32_t qs[3]; - uint_fast32_t q; - uint_fast64_t x64, sig64Z; - struct uint128 y, term; - uint_fast64_t sigZExtra; - struct uint128 sigZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) { - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA.v64 | sigA.v0) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) return a; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFE; - expA &= 1; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sig32A = sigA.v64>>17; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sig32Z >>= 1; - rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 12 ); - } else { - rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 13 ); - } - qs[2] = sig32Z; - rem.v64 -= (uint_fast64_t) sig32Z * sig32Z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem.v64>>2) * (uint_fast64_t) recipSqrt32)>>32; - x64 = (uint_fast64_t) sig32Z<<32; - sig64Z = x64 + ((uint_fast64_t) q<<3); - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_mul64ByShifted32To128( x64 + sig64Z, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - sig64Z -= 1<<3; - } - qs[1] = q; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((rem.v64>>2) * recipSqrt32)>>32; - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - sig64Z <<= 1; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_shortShiftLeft128( 0, sig64Z, 32 ); - term = softfloat_add128( term.v64, term.v0, 0, (uint_fast64_t) q<<6 ); - term = softfloat_mul128By32( term.v64, term.v0, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - } - qs[0] = q; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((rem.v64>>2) * recipSqrt32)>>32) + 2; - sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); - term = softfloat_shortShiftLeft128( 0, qs[1], 53 ); - sigZ = - softfloat_add128( - (uint_fast64_t) qs[2]<<18, ((uint_fast64_t) qs[0]<<24) + (q>>5), - term.v64, term.v0 - ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xF) <= 2 ) { - q &= ~3; - sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); - y = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, 6 ); - y.v0 |= sigZExtra>>58; - term = softfloat_sub128( y.v64, y.v0, 0, q ); - y = softfloat_mul64ByShifted32To128( term.v0, q ); - term = softfloat_mul64ByShifted32To128( term.v64, q ); - term = softfloat_add128( term.v64, term.v0, 0, y.v64 ); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 20 ); - term = softfloat_sub128( term.v64, term.v0, rem.v64, rem.v0 ); - /*-------------------------------------------------------------------- - | The concatenation of `term' and `y.v0' is now the negative remainder - | (3 words altogether). - *--------------------------------------------------------------------*/ - if ( term.v64 & UINT64_C( 0x8000000000000000 ) ) { - sigZExtra |= 1; - } else { - if ( term.v64 | term.v0 | y.v0 ) { - if ( sigZExtra ) { - --sigZExtra; - } else { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); - sigZExtra = ~0; - } - } - } - } - return softfloat_roundPackToF128( 0, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_sub.c b/deps/SoftFloat-3e/source/f128_sub.c deleted file mode 100644 index 5181cc5ecd1f..000000000000 --- a/deps/SoftFloat-3e/source/f128_sub.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_sub( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF128 : softfloat_addMagsF128; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_extF80.c b/deps/SoftFloat-3e/source/f128_to_extF80.c deleted file mode 100644 index ec169c0ffaea..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_extF80.c +++ /dev/null @@ -1,109 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f128_to_extF80( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64, frac0; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp32_sig128 normExpSig; - struct uint128 sig128; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ); - frac0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 | frac0 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! (frac64 | frac0) ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF128Sig( frac64, frac0 ); - exp = normExpSig.exp; - frac64 = normExpSig.sig.v64; - frac0 = normExpSig.sig.v0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig128 = - softfloat_shortShiftLeft128( - frac64 | UINT64_C( 0x0001000000000000 ), frac0, 15 ); - return softfloat_roundPackToExtF80( sign, exp, sig128.v64, sig128.v0, 80 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f16.c b/deps/SoftFloat-3e/source/f128_to_f16.c deleted file mode 100644 index 5a8ee721297b..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f16.c +++ /dev/null @@ -1,95 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f128_to_f16( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = softfloat_shortShiftRightJam64( frac64, 34 ); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, frac16 | 0x4000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f32.c b/deps/SoftFloat-3e/source/f128_to_f32.c deleted file mode 100644 index 07e4a80df65d..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f32.c +++ /dev/null @@ -1,95 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f128_to_f32( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64; - struct commonNaN commonNaN; - uint_fast32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f64.c b/deps/SoftFloat-3e/source/f128_to_f64.c deleted file mode 100644 index f791938b4190..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f64.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f128_to_f64( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64, frac0; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct uint128 frac128; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ); - frac0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 | frac0 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac128 = softfloat_shortShiftLeft128( frac64, frac0, 14 ); - frac64 = frac128.v64 | (frac128.v0 != 0); - if ( ! (exp | frac64) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return - softfloat_roundPackToF64( - sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i32.c b/deps/SoftFloat-3e/source/f128_to_i32.c deleted file mode 100644 index 16c4a3ccdace..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i32.c +++ /dev/null @@ -1,85 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f128_to_i32( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig64 | sig0) ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sig64 |= (sig0 != 0); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c deleted file mode 100644 index 18cfeaee5442..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f128_to_i32_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI64( uiA64 ); - if ( shiftDist < 18 ) { - if ( - sign && (shiftDist == 17) - && (sig64 < UINT64_C( 0x0000000000020000 )) - ) { - if ( exact && sig64 ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - absZ = sig64>>shiftDist; - if ( - exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f128_to_i64( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - struct uint128 sig128; - struct uint64_extra sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -15 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); - sig64 = sigExtra.v; - sig0 = sigExtra.extra; - } - return softfloat_roundToI64( sign, sig64, sig0, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c deleted file mode 100644 index e2cc62e27ebe..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f128_to_i64_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - int_fast8_t negShiftDist; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist < 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -14 ) { - if ( - (uiA64 == UINT64_C( 0xC03E000000000000 )) - && (sig0 < UINT64_C( 0x0002000000000000 )) - ) { - if ( exact && sig0 ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - negShiftDist = -shiftDist; - absZ = sig64<>(shiftDist & 63); - if ( exact && (uint64_t) (sig0<>shiftDist; - if ( exact && (sig0 || (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) { - sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - } - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c deleted file mode 100644 index 92facd517819..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c +++ /dev/null @@ -1,89 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f128_to_ui32_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI64( uiA64 ); - if ( sign || (shiftDist < 17) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - z = sig64>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - f128_to_ui64( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - struct uint128 sig128; - struct uint64_extra sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -15 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); - sig64 = sigExtra.v; - sig0 = sigExtra.extra; - } - return softfloat_roundToUI64( sign, sig64, sig0, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c deleted file mode 100644 index edeafd3c814b..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c +++ /dev/null @@ -1,105 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f128_to_ui64_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - int_fast8_t negShiftDist; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist < 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( sign || (shiftDist < -15) ) goto invalid; - sig64 |= UINT64_C( 0x0001000000000000 ); - negShiftDist = -shiftDist; - z = sig64<>(shiftDist & 63); - if ( exact && (uint64_t) (sig0<>shiftDist; - if ( exact && (sig0 || (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_add( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF16UI( uiA ^ uiB ) ) { - return softfloat_subMagsF16( uiA, uiB ); - } else { - return softfloat_addMagsF16( uiA, uiB ); - } -#else - magsFuncPtr = - signF16UI( uiA ^ uiB ) ? softfloat_subMagsF16 : softfloat_addMagsF16; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_div.c b/deps/SoftFloat-3e/source/f16_div.c deleted file mode 100644 index 77f9a2cd2b89..000000000000 --- a/deps/SoftFloat-3e/source/f16_div.c +++ /dev/null @@ -1,186 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extern const uint16_t softfloat_approxRecip_1k0s[]; -extern const uint16_t softfloat_approxRecip_1k1s[]; - -float16_t f16_div( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signZ; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; -#ifdef SOFTFLOAT_FAST_DIV32TO16 - uint_fast32_t sig32A; - uint_fast16_t sigZ; -#else - int index; - uint16_t r0; - uint_fast16_t sigZ, rem; -#endif - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0xE; - sigA |= 0x0400; - sigB |= 0x0400; -#ifdef SOFTFLOAT_FAST_DIV32TO16 - if ( sigA < sigB ) { - --expZ; - sig32A = (uint_fast32_t) sigA<<15; - } else { - sig32A = (uint_fast32_t) sigA<<14; - } - sigZ = sig32A / sigB; - if ( ! (sigZ & 7) ) sigZ |= ((uint_fast32_t) sigB * sigZ != sig32A); -#else - if ( sigA < sigB ) { - --expZ; - sigA <<= 5; - } else { - sigA <<= 4; - } - index = sigB>>6 & 0xF; - r0 = softfloat_approxRecip_1k0s[index] - - (((uint_fast32_t) softfloat_approxRecip_1k1s[index] - * (sigB & 0x3F)) - >>10); - sigZ = ((uint_fast32_t) sigA * r0)>>16; - rem = (sigA<<10) - sigZ * sigB; - sigZ += (rem * (uint_fast32_t) r0)>>26; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ++sigZ; - if ( ! (sigZ & 7) ) { - sigZ &= ~1; - rem = (sigA<<10) - sigZ * sigB; - if ( rem & 0x8000 ) { - sigZ -= 2; - } else { - if ( rem ) sigZ |= 1; - } - } -#endif - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF16UI( signZ, 0x1F, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF16UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_eq.c b/deps/SoftFloat-3e/source/f16_eq.c deleted file mode 100644 index 692fa035f94b..000000000000 --- a/deps/SoftFloat-3e/source/f16_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_eq( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f16_eq_signaling.c b/deps/SoftFloat-3e/source/f16_eq_signaling.c deleted file mode 100644 index c1e7a509ca90..000000000000 --- a/deps/SoftFloat-3e/source/f16_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_eq_signaling( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f16_isSignalingNaN.c b/deps/SoftFloat-3e/source/f16_isSignalingNaN.c deleted file mode 100644 index 3eb3d4cc6bab..000000000000 --- a/deps/SoftFloat-3e/source/f16_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_isSignalingNaN( float16_t a ) -{ - union ui16_f16 uA; - - uA.f = a; - return softfloat_isSigNaNF16UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_le.c b/deps/SoftFloat-3e/source/f16_le.c deleted file mode 100644 index d7313debd54e..000000000000 --- a/deps/SoftFloat-3e/source/f16_le.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_le( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_le_quiet.c b/deps/SoftFloat-3e/source/f16_le_quiet.c deleted file mode 100644 index 15181c2602f6..000000000000 --- a/deps/SoftFloat-3e/source/f16_le_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_le_quiet( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_lt.c b/deps/SoftFloat-3e/source/f16_lt.c deleted file mode 100644 index 7745699a2c0a..000000000000 --- a/deps/SoftFloat-3e/source/f16_lt.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_lt( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_lt_quiet.c b/deps/SoftFloat-3e/source/f16_lt_quiet.c deleted file mode 100644 index a31e4a13f439..000000000000 --- a/deps/SoftFloat-3e/source/f16_lt_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_lt_quiet( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_mul.c b/deps/SoftFloat-3e/source/f16_mul.c deleted file mode 100644 index a47cab8ce353..000000000000 --- a/deps/SoftFloat-3e/source/f16_mul.c +++ /dev/null @@ -1,140 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_mul( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signZ; - uint_fast16_t magBits; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; - uint_fast32_t sig32Z; - uint_fast16_t sigZ, uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0xF; - sigA = (sigA | 0x0400)<<4; - sigB = (sigB | 0x0400)<<5; - sig32Z = (uint_fast32_t) sigA * sigB; - sigZ = sig32Z>>16; - if ( sig32Z & 0xFFFF ) sigZ |= 1; - if ( sigZ < 0x4000 ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - } else { - uiZ = packToF16UI( signZ, 0x1F, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF16UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_mulAdd.c b/deps/SoftFloat-3e/source/f16_mulAdd.c deleted file mode 100644 index e97571ac509a..000000000000 --- a/deps/SoftFloat-3e/source/f16_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_mulAdd( float16_t a, float16_t b, float16_t c ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - union ui16_f16 uC; - uint_fast16_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF16( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_rem.c b/deps/SoftFloat-3e/source/f16_rem.c deleted file mode 100644 index 0ffa498a1747..000000000000 --- a/deps/SoftFloat-3e/source/f16_rem.c +++ /dev/null @@ -1,171 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_rem( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - int_fast8_t expB; - uint_fast16_t sigB; - struct exp8_sig16 normExpSig; - uint16_t rem; - int_fast8_t expDiff; - uint_fast16_t q; - uint32_t recip32, q32; - uint16_t altRem, meanRem; - bool signRem; - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | 0x0400; - sigB |= 0x0400; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 3; - if ( expDiff ) { - rem <<= 2; - q = 0; - } else { - rem <<= 3; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( (uint_fast32_t) sigB<<21 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 4; - expDiff -= 31; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | which is believed to be the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 3; - for (;;) { - q32 = (rem * (uint_fast64_t) recip32)>>16; - if ( expDiff < 0 ) break; - rem = -((uint_fast16_t) q32 * sigB); - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -30 here.) - *--------------------------------------------------------------------*/ - q32 >>= ~expDiff & 31; - q = q32; - rem = (rem<<(expDiff + 30)) - q * sigB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & 0x8000) ); - meanRem = rem + altRem; - if ( (meanRem & 0x8000) || (! meanRem && (q & 1)) ) rem = altRem; - signRem = signA; - if ( 0x8000 <= rem ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF16( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_roundToInt.c b/deps/SoftFloat-3e/source/f16_roundToInt.c deleted file mode 100644 index a567d51d9fd5..000000000000 --- a/deps/SoftFloat-3e/source/f16_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_roundToInt( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t uiZ, lastBitMask, roundBitsMask; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0xE ) { - if ( !(uint16_t) (uiA<<1) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF16UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF16UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0xE ) uiZ |= packToF16UI( 0, 0xF, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF16UI( 1, 0xF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF16UI( 0, 0xF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF16UI( 0, 0xF, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x19 <= exp ) { - if ( (exp == 0x1F) && fracF16UI( uiA ) ) { - uiZ = softfloat_propagateNaNF16UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast16_t) 1<<(0x19 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF16UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_sqrt.c b/deps/SoftFloat-3e/source/f16_sqrt.c deleted file mode 100644 index 47a3bbf148bb..000000000000 --- a/deps/SoftFloat-3e/source/f16_sqrt.c +++ /dev/null @@ -1,136 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; - -float16_t f16_sqrt( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA, uiZ; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; - int index; - uint_fast16_t r0; - uint_fast32_t ESqrR0; - uint16_t sigma0; - uint_fast16_t recipSqrt16, sigZ, shiftedSigZ; - uint16_t negRem; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF16UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0xF)>>1) + 0xE; - expA &= 1; - sigA |= 0x0400; - index = (sigA>>6 & 0xE) + expA; - r0 = softfloat_approxRecipSqrt_1k0s[index] - - (((uint_fast32_t) softfloat_approxRecipSqrt_1k1s[index] - * (sigA & 0x7F)) - >>11); - ESqrR0 = ((uint_fast32_t) r0 * r0)>>1; - if ( expA ) ESqrR0 >>= 1; - sigma0 = ~(uint_fast16_t) ((ESqrR0 * sigA)>>16); - recipSqrt16 = r0 + (((uint_fast32_t) r0 * sigma0)>>25); - if ( ! (recipSqrt16 & 0x8000) ) recipSqrt16 = 0x8000; - sigZ = ((uint_fast32_t) (sigA<<5) * recipSqrt16)>>16; - if ( expA ) sigZ >>= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ++sigZ; - if ( ! (sigZ & 7) ) { - shiftedSigZ = sigZ>>1; - negRem = shiftedSigZ * shiftedSigZ; - sigZ &= ~1; - if ( negRem & 0x8000 ) { - sigZ |= 1; - } else { - if ( negRem ) --sigZ; - } - } - return softfloat_roundPackToF16( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_sub.c b/deps/SoftFloat-3e/source/f16_sub.c deleted file mode 100644 index 03a87cf32530..000000000000 --- a/deps/SoftFloat-3e/source/f16_sub.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_sub( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF16UI( uiA ^ uiB ) ) { - return softfloat_addMagsF16( uiA, uiB ); - } else { - return softfloat_subMagsF16( uiA, uiB ); - } -#else - magsFuncPtr = - signF16UI( uiA ^ uiB ) ? softfloat_addMagsF16 : softfloat_subMagsF16; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_extF80.c b/deps/SoftFloat-3e/source/f16_to_extF80.c deleted file mode 100644 index 99c2dfc74660..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f16_to_extF80( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp8_sig16 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3FF0 ); - uiZ0 = (uint_fast64_t) (frac | 0x0400)<<53; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_extF80M.c b/deps/SoftFloat-3e/source/f16_to_extF80M.c deleted file mode 100644 index 7f2d53458d81..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f16_to_extF80M( float16_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f16_to_extF80( a ); - -} - -#else - -void f16_to_extF80M( float16_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui16_f16 uA; - uint16_t uiA; - bool sign; - int_fast8_t exp; - uint16_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint32_t uiZ32; - struct exp8_sig16 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ32 = 0x80000000; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ32 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3FF0 ); - uiZ32 = 0x80000000 | (uint32_t) frac<<21; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = (uint64_t) uiZ32<<32; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f16_to_f128.c b/deps/SoftFloat-3e/source/f16_to_f128.c deleted file mode 100644 index c4b81dc840d1..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f128.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f16_to_f128( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp8_sig16 normExpSig; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ.v64 = packToF128UI64( sign, exp + 0x3FF0, (uint_fast64_t) frac<<38 ); - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_f128M.c b/deps/SoftFloat-3e/source/f16_to_f128M.c deleted file mode 100644 index b4fc873b5627..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f128M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f16_to_f128M( float16_t a, float128_t *zPtr ) -{ - - *zPtr = f16_to_f128( a ); - -} - -#else - -void f16_to_f128M( float16_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui16_f16 uA; - uint16_t uiA; - bool sign; - int_fast8_t exp; - uint16_t frac; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp8_sig16 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ96 = packToF128UI96( sign, exp + 0x3FF0, (uint32_t) frac<<6 ); - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f16_to_f32.c b/deps/SoftFloat-3e/source/f16_to_f32.c deleted file mode 100644 index a219454bf286..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f32.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f16_to_f32( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - uint_fast32_t uiZ; - struct exp8_sig16 normExpSig; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF32UI( sign, exp + 0x70, (uint_fast32_t) frac<<13 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_f64.c b/deps/SoftFloat-3e/source/f16_to_f64.c deleted file mode 100644 index 7e87c25f4f06..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f64.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f16_to_f64( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct exp8_sig16 normExpSig; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF64UI( sign, exp + 0x3F0, (uint_fast64_t) frac<<42 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i32.c b/deps/SoftFloat-3e/source/f16_to_i32.c deleted file mode 100644 index 805c4e55038c..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i32.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f16_to_i32( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - int_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( 0 <= shiftDist ) { - sig32 <<= shiftDist; - return sign ? -sig32 : sig32; - } - shiftDist = exp - 0x0D; - if ( 0 < shiftDist ) sig32 <<= shiftDist; - } - return - softfloat_roundToI32( - sign, (uint_fast32_t) sig32, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c deleted file mode 100644 index b1f9963718a9..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f16_to_i32_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - int_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; - return sign ? -alignedSig : alignedSig; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i64.c b/deps/SoftFloat-3e/source/f16_to_i64.c deleted file mode 100644 index e3c0065f619e..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i64.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f16_to_i64( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - int_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( 0 <= shiftDist ) { - sig32 <<= shiftDist; - return sign ? -sig32 : sig32; - } - shiftDist = exp - 0x0D; - if ( 0 < shiftDist ) sig32 <<= shiftDist; - } - return - softfloat_roundToI32( - sign, (uint_fast32_t) sig32, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c deleted file mode 100644 index a5a6a077e6ff..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f16_to_i64_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - int_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; - return sign ? -alignedSig : alignedSig; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui32.c b/deps/SoftFloat-3e/source/f16_to_ui32.c deleted file mode 100644 index 5371ca339581..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f16_to_ui32( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - uint_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( (0 <= shiftDist) && ! sign ) { - return sig32< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f16_to_ui32_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - uint_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( sign || (exp == 0x1F) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui64.c b/deps/SoftFloat-3e/source/f16_to_ui64.c deleted file mode 100644 index e6cb000f1e27..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui64.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f16_to_ui64( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - uint_fast32_t sig32; - int_fast8_t shiftDist; -#ifndef SOFTFLOAT_FAST_INT64 - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( (0 <= shiftDist) && ! sign ) { - return sig32<>12, (uint_fast64_t) sig32<<52, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = 0; - extSig[indexWord( 3, 1 )] = sig32>>12; - extSig[indexWord( 3, 0 )] = sig32<<20; - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c deleted file mode 100644 index b4f975f83339..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f16_to_ui64_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - uint_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( sign || (exp == 0x1F) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; - -} - diff --git a/deps/SoftFloat-3e/source/f32_add.c b/deps/SoftFloat-3e/source/f32_add.c deleted file mode 100644 index 70e03e7f94fe..000000000000 --- a/deps/SoftFloat-3e/source/f32_add.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_add( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF32UI( uiA ^ uiB ) ) { - return softfloat_subMagsF32( uiA, uiB ); - } else { - return softfloat_addMagsF32( uiA, uiB ); - } -#else - magsFuncPtr = - signF32UI( uiA ^ uiB ) ? softfloat_subMagsF32 : softfloat_addMagsF32; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_div.c b/deps/SoftFloat-3e/source/f32_div.c deleted file mode 100644 index 05ec701f76ff..000000000000 --- a/deps/SoftFloat-3e/source/f32_div.c +++ /dev/null @@ -1,180 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_div( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signZ; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; -#ifdef SOFTFLOAT_FAST_DIV64TO32 - uint_fast64_t sig64A; - uint_fast32_t sigZ; -#else - uint_fast32_t sigZ; - uint_fast64_t rem; -#endif - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x7E; - sigA |= 0x00800000; - sigB |= 0x00800000; -#ifdef SOFTFLOAT_FAST_DIV64TO32 - if ( sigA < sigB ) { - --expZ; - sig64A = (uint_fast64_t) sigA<<31; - } else { - sig64A = (uint_fast64_t) sigA<<30; - } - sigZ = sig64A / sigB; - if ( ! (sigZ & 0x3F) ) sigZ |= ((uint_fast64_t) sigB * sigZ != sig64A); -#else - if ( sigA < sigB ) { - --expZ; - sigA <<= 8; - } else { - sigA <<= 7; - } - sigB <<= 8; - sigZ = ((uint_fast64_t) sigA * softfloat_approxRecip32_1( sigB ))>>32; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ += 2; - if ( (sigZ & 0x3F) < 2 ) { - sigZ &= ~3; -#ifdef SOFTFLOAT_FAST_INT64 - rem = ((uint_fast64_t) sigA<<31) - (uint_fast64_t) sigZ * sigB; -#else - rem = ((uint_fast64_t) sigA<<32) - (uint_fast64_t) (sigZ<<1) * sigB; -#endif - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - sigZ -= 4; - } else { - if ( rem ) sigZ |= 1; - } - } -#endif - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF32UI( signZ, 0xFF, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF32UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_eq.c b/deps/SoftFloat-3e/source/f32_eq.c deleted file mode 100644 index 801bbfd73453..000000000000 --- a/deps/SoftFloat-3e/source/f32_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_eq( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f32_eq_signaling.c b/deps/SoftFloat-3e/source/f32_eq_signaling.c deleted file mode 100644 index 4c610ffae87e..000000000000 --- a/deps/SoftFloat-3e/source/f32_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_eq_signaling( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f32_isSignalingNaN.c b/deps/SoftFloat-3e/source/f32_isSignalingNaN.c deleted file mode 100644 index f5954cbbc441..000000000000 --- a/deps/SoftFloat-3e/source/f32_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_isSignalingNaN( float32_t a ) -{ - union ui32_f32 uA; - - uA.f = a; - return softfloat_isSigNaNF32UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_le.c b/deps/SoftFloat-3e/source/f32_le.c deleted file mode 100644 index d89d1e88df72..000000000000 --- a/deps/SoftFloat-3e/source/f32_le.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_le( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA || ! (uint32_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_le_quiet.c b/deps/SoftFloat-3e/source/f32_le_quiet.c deleted file mode 100644 index c2d4297a2928..000000000000 --- a/deps/SoftFloat-3e/source/f32_le_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_le_quiet( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA || ! (uint32_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_lt.c b/deps/SoftFloat-3e/source/f32_lt.c deleted file mode 100644 index 5b5fd22821ad..000000000000 --- a/deps/SoftFloat-3e/source/f32_lt.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_lt( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_lt_quiet.c b/deps/SoftFloat-3e/source/f32_lt_quiet.c deleted file mode 100644 index 015388143711..000000000000 --- a/deps/SoftFloat-3e/source/f32_lt_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_lt_quiet( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_mul.c b/deps/SoftFloat-3e/source/f32_mul.c deleted file mode 100644 index f5c856002f62..000000000000 --- a/deps/SoftFloat-3e/source/f32_mul.c +++ /dev/null @@ -1,137 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_mul( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signZ; - uint_fast32_t magBits; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; - uint_fast32_t sigZ, uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x7F; - sigA = (sigA | 0x00800000)<<7; - sigB = (sigB | 0x00800000)<<8; - sigZ = softfloat_shortShiftRightJam64( (uint_fast64_t) sigA * sigB, 32 ); - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - } else { - uiZ = packToF32UI( signZ, 0xFF, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF32UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_mulAdd.c b/deps/SoftFloat-3e/source/f32_mulAdd.c deleted file mode 100644 index 9a28e212ce13..000000000000 --- a/deps/SoftFloat-3e/source/f32_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_mulAdd( float32_t a, float32_t b, float32_t c ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - union ui32_f32 uC; - uint_fast32_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF32( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_rem.c b/deps/SoftFloat-3e/source/f32_rem.c deleted file mode 100644 index b29bf416e461..000000000000 --- a/deps/SoftFloat-3e/source/f32_rem.c +++ /dev/null @@ -1,168 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_rem( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - int_fast16_t expB; - uint_fast32_t sigB; - struct exp16_sig32 normExpSig; - uint32_t rem; - int_fast16_t expDiff; - uint32_t q, recip32, altRem, meanRem; - bool signRem; - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | 0x00800000; - sigB |= 0x00800000; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 6; - if ( expDiff ) { - rem <<= 5; - q = 0; - } else { - rem <<= 6; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( sigB<<8 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 7; - expDiff -= 31; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | which is believed to be the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 6; - for (;;) { - q = (rem * (uint_fast64_t) recip32)>>32; - if ( expDiff < 0 ) break; - rem = -(q * (uint32_t) sigB); - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -30 here.) - *--------------------------------------------------------------------*/ - q >>= ~expDiff & 31; - rem = (rem<<(expDiff + 30)) - q * (uint32_t) sigB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & 0x80000000) ); - meanRem = rem + altRem; - if ( (meanRem & 0x80000000) || (! meanRem && (q & 1)) ) rem = altRem; - signRem = signA; - if ( 0x80000000 <= rem ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF32( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_roundToInt.c b/deps/SoftFloat-3e/source/f32_roundToInt.c deleted file mode 100644 index 305af79ddef0..000000000000 --- a/deps/SoftFloat-3e/source/f32_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t uiZ, lastBitMask, roundBitsMask; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x7E ) { - if ( !(uint32_t) (uiA<<1) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF32UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF32UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x7E ) uiZ |= packToF32UI( 0, 0x7F, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF32UI( 1, 0x7F, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF32UI( 0, 0x7F, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF32UI( 0, 0x7F, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x96 <= exp ) { - if ( (exp == 0xFF) && fracF32UI( uiA ) ) { - uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast32_t) 1<<(0x96 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF32UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_sqrt.c b/deps/SoftFloat-3e/source/f32_sqrt.c deleted file mode 100644 index 9263bde595e2..000000000000 --- a/deps/SoftFloat-3e/source/f32_sqrt.c +++ /dev/null @@ -1,121 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_sqrt( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA, uiZ; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; - uint_fast32_t sigZ, shiftedSigZ; - uint32_t negRem; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x7F)>>1) + 0x7E; - expA &= 1; - sigA = (sigA | 0x00800000)<<8; - sigZ = - ((uint_fast64_t) sigA * softfloat_approxRecipSqrt32_1( expA, sigA )) - >>32; - if ( expA ) sigZ >>= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ += 2; - if ( (sigZ & 0x3F) < 2 ) { - shiftedSigZ = sigZ>>2; - negRem = shiftedSigZ * shiftedSigZ; - sigZ &= ~3; - if ( negRem & 0x80000000 ) { - sigZ |= 1; - } else { - if ( negRem ) --sigZ; - } - } - return softfloat_roundPackToF32( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_sub.c b/deps/SoftFloat-3e/source/f32_sub.c deleted file mode 100644 index 383484dae16a..000000000000 --- a/deps/SoftFloat-3e/source/f32_sub.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_sub( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF32UI( uiA ^ uiB ) ) { - return softfloat_addMagsF32( uiA, uiB ); - } else { - return softfloat_subMagsF32( uiA, uiB ); - } -#else - magsFuncPtr = - signF32UI( uiA ^ uiB ) ? softfloat_addMagsF32 : softfloat_subMagsF32; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_extF80.c b/deps/SoftFloat-3e/source/f32_to_extF80.c deleted file mode 100644 index 742ed649c58c..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f32_to_extF80( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp16_sig32 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3F80 ); - uiZ0 = (uint_fast64_t) (frac | 0x00800000)<<40; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_extF80M.c b/deps/SoftFloat-3e/source/f32_to_extF80M.c deleted file mode 100644 index af7e32a76eac..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f32_to_extF80( a ); - -} - -#else - -void f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui32_f32 uA; - uint32_t uiA; - bool sign; - int_fast16_t exp; - uint32_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint32_t uiZ32; - struct exp16_sig32 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ32 = 0x80000000; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ32 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3F80 ); - uiZ32 = 0x80000000 | (uint32_t) frac<<8; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = (uint64_t) uiZ32<<32; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f32_to_f128.c b/deps/SoftFloat-3e/source/f32_to_f128.c deleted file mode 100644 index 6a765a44e493..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f128.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f32_to_f128( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp16_sig32 normExpSig; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ.v64 = packToF128UI64( sign, exp + 0x3F80, (uint_fast64_t) frac<<25 ); - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_f128M.c b/deps/SoftFloat-3e/source/f32_to_f128M.c deleted file mode 100644 index ee7e6b367c9a..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f128M.c +++ /dev/null @@ -1,115 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f32_to_f128M( float32_t a, float128_t *zPtr ) -{ - - *zPtr = f32_to_f128( a ); - -} - -#else - -void f32_to_f128M( float32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui32_f32 uA; - uint32_t uiA; - bool sign; - int_fast16_t exp; - uint32_t frac, uiZ64; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp16_sig32 normExpSig; - uint64_t frac64; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = 0; - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac64 = (uint64_t) frac<<25; - uiZ96 = packToF128UI96( sign, exp + 0x3F80, frac64>>32 ); - uiZ64 = frac64; - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f32_to_f16.c b/deps/SoftFloat-3e/source/f32_to_f16.c deleted file mode 100644 index a9e77b775aa8..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f16.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f32_to_f16( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = frac>>9 | ((frac & 0x1FF) != 0); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF16( sign, exp - 0x71, frac16 | 0x4000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_f64.c b/deps/SoftFloat-3e/source/f32_to_f64.c deleted file mode 100644 index 4f97519e8637..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f64.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f32_to_f64( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct exp16_sig32 normExpSig; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF64UI( sign, exp + 0x380, (uint_fast64_t) frac<<29 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i32.c b/deps/SoftFloat-3e/source/f32_to_i32.c deleted file mode 100644 index 7d0356fbe3b9..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f32_to_i32( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - uint_fast64_t sig64; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0xFF) && sig ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<32; - shiftDist = 0xAA - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c deleted file mode 100644 index 7652f2ebb024..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c +++ /dev/null @@ -1,89 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f32_to_i32_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x9E - exp; - if ( 32 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( shiftDist <= 0 ) { - if ( uiA == packToF32UI( 1, 0x9E, 0 ) ) return -0x7FFFFFFF - 1; - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig | 0x00800000)<<8; - absZ = sig>>shiftDist; - if ( exact && ((uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f32_to_i64( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - uint_fast64_t sig64, extra; - struct uint64_extra sig64Extra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; -#ifdef SOFTFLOAT_FAST_INT64 - sig64 = (uint_fast64_t) sig<<40; - extra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); - sig64 = sig64Extra.v; - extra = sig64Extra.extra; - } - return softfloat_roundToI64( sign, sig64, extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = sig<<8; - extSig[indexWord( 3, 1 )] = 0; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c deleted file mode 100644 index 397ddf6d0dc5..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c +++ /dev/null @@ -1,94 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t sig64; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( shiftDist <= 0 ) { - if ( uiA == packToF32UI( 1, 0xBE, 0 ) ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<40; - absZ = sig64>>shiftDist; - shiftDist = 40 - shiftDist; - if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sign ? -absZ : absZ; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui32.c b/deps/SoftFloat-3e/source/f32_to_ui32.c deleted file mode 100644 index cb47d9458f0d..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f32_to_ui32( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - uint_fast64_t sig64; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0xFF) && sig ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<32; - shiftDist = 0xAA - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c deleted file mode 100644 index cdeb75f9f2ca..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f32_to_ui32_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x9E - exp; - if ( 32 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig | 0x00800000)<<8; - z = sig>>shiftDist; - if ( exact && (z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f32_to_ui64( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - uint_fast64_t sig64, extra; - struct uint64_extra sig64Extra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; -#ifdef SOFTFLOAT_FAST_INT64 - sig64 = (uint_fast64_t) sig<<40; - extra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); - sig64 = sig64Extra.v; - extra = sig64Extra.extra; - } - return softfloat_roundToUI64( sign, sig64, extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = sig<<8; - extSig[indexWord( 3, 1 )] = 0; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c deleted file mode 100644 index c0fe54f6e195..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c +++ /dev/null @@ -1,90 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f32_to_ui64_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t sig64, z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<40; - z = sig64>>shiftDist; - shiftDist = 40 - shiftDist; - if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - -} - diff --git a/deps/SoftFloat-3e/source/f64_add.c b/deps/SoftFloat-3e/source/f64_add.c deleted file mode 100644 index 42f840dc59bf..000000000000 --- a/deps/SoftFloat-3e/source/f64_add.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_add( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsF64( uiA, uiB, signA ); - } else { - return softfloat_subMagsF64( uiA, uiB, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF64 : softfloat_subMagsF64; - return (*magsFuncPtr)( uiA, uiB, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f64_div.c b/deps/SoftFloat-3e/source/f64_div.c deleted file mode 100644 index 9c967bb740ab..000000000000 --- a/deps/SoftFloat-3e/source/f64_div.c +++ /dev/null @@ -1,172 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_div( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t recip32, sig32Z, doubleTerm; - uint_fast64_t rem; - uint32_t q; - uint_fast64_t sigZ; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FE; - sigA |= UINT64_C( 0x0010000000000000 ); - sigB |= UINT64_C( 0x0010000000000000 ); - if ( sigA < sigB ) { - --expZ; - sigA <<= 11; - } else { - sigA <<= 10; - } - sigB <<= 11; - recip32 = softfloat_approxRecip32_1( sigB>>32 ) - 2; - sig32Z = ((uint32_t) (sigA>>32) * (uint_fast64_t) recip32)>>32; - doubleTerm = sig32Z<<1; - rem = - ((sigA - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); - q = (((uint32_t) (rem>>32) * (uint_fast64_t) recip32)>>32) + 4; - sigZ = ((uint_fast64_t) sig32Z<<32) + ((uint_fast64_t) q<<4); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (sigZ & 0x1FF) < 4<<4 ) { - q &= ~7; - sigZ &= ~(uint_fast64_t) 0x7F; - doubleTerm = q<<1; - rem = - ((rem - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - sigZ -= 1<<7; - } else { - if ( rem ) sigZ |= 1; - } - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF64UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_eq.c b/deps/SoftFloat-3e/source/f64_eq.c deleted file mode 100644 index 36020037953e..000000000000 --- a/deps/SoftFloat-3e/source/f64_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_eq( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); - -} - diff --git a/deps/SoftFloat-3e/source/f64_eq_signaling.c b/deps/SoftFloat-3e/source/f64_eq_signaling.c deleted file mode 100644 index 5daa17937320..000000000000 --- a/deps/SoftFloat-3e/source/f64_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_eq_signaling( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); - -} - diff --git a/deps/SoftFloat-3e/source/f64_isSignalingNaN.c b/deps/SoftFloat-3e/source/f64_isSignalingNaN.c deleted file mode 100644 index e5d38321ecdd..000000000000 --- a/deps/SoftFloat-3e/source/f64_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_isSignalingNaN( float64_t a ) -{ - union ui64_f64 uA; - - uA.f = a; - return softfloat_isSigNaNF64UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_le.c b/deps/SoftFloat-3e/source/f64_le.c deleted file mode 100644 index 0b43d0467706..000000000000 --- a/deps/SoftFloat-3e/source/f64_le.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_le( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_le_quiet.c b/deps/SoftFloat-3e/source/f64_le_quiet.c deleted file mode 100644 index 832eee7a76bf..000000000000 --- a/deps/SoftFloat-3e/source/f64_le_quiet.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_le_quiet( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_lt.c b/deps/SoftFloat-3e/source/f64_lt.c deleted file mode 100644 index 49ee05be031b..000000000000 --- a/deps/SoftFloat-3e/source/f64_lt.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_lt( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA && ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_lt_quiet.c b/deps/SoftFloat-3e/source/f64_lt_quiet.c deleted file mode 100644 index d64088054927..000000000000 --- a/deps/SoftFloat-3e/source/f64_lt_quiet.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_lt_quiet( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA && ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_mul.c b/deps/SoftFloat-3e/source/f64_mul.c deleted file mode 100644 index 222e91dce4b7..000000000000 --- a/deps/SoftFloat-3e/source/f64_mul.c +++ /dev/null @@ -1,150 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_mul( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signZ; - uint_fast64_t magBits; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint128 sig128Z; -#else - uint32_t sig128Z[4]; -#endif - uint_fast64_t sigZ, uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FF; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; -#ifdef SOFTFLOAT_FAST_INT64 - sig128Z = softfloat_mul64To128( sigA, sigB ); - sigZ = sig128Z.v64 | (sig128Z.v0 != 0); -#else - softfloat_mul64To128M( sigA, sigB, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; - if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; -#endif - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - } else { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF64UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_mulAdd.c b/deps/SoftFloat-3e/source/f64_mulAdd.c deleted file mode 100644 index fea3d968bf1d..000000000000 --- a/deps/SoftFloat-3e/source/f64_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_mulAdd( float64_t a, float64_t b, float64_t c ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - union ui64_f64 uC; - uint_fast64_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF64( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_rem.c b/deps/SoftFloat-3e/source/f64_rem.c deleted file mode 100644 index ffce679aa30d..000000000000 --- a/deps/SoftFloat-3e/source/f64_rem.c +++ /dev/null @@ -1,189 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_rem( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - int_fast16_t expB; - uint_fast64_t sigB; - struct exp16_sig64 normExpSig; - uint64_t rem; - int_fast16_t expDiff; - uint32_t q, recip32; - uint_fast64_t q64; - uint64_t altRem, meanRem; - bool signRem; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA < expB - 1 ) return a; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | UINT64_C( 0x0010000000000000 ); - sigB |= UINT64_C( 0x0010000000000000 ); - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 9; - if ( expDiff ) { - rem <<= 8; - q = 0; - } else { - rem <<= 9; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( sigB>>21 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 9; - expDiff -= 30; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 9; - for (;;) { - q64 = (uint32_t) (rem>>32) * (uint_fast64_t) recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; -#ifdef SOFTFLOAT_FAST_INT64 - rem <<= 29; -#else - rem = (uint_fast64_t) (uint32_t) (rem>>3)<<32; -#endif - rem -= q * (uint64_t) sigB; - if ( rem & UINT64_C( 0x8000000000000000 ) ) rem += sigB; - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = (rem<<(expDiff + 30)) - q * (uint64_t) sigB; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - altRem = rem + sigB; - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = rem + altRem; - if ( - (meanRem & UINT64_C( 0x8000000000000000 )) || (! meanRem && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF64( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_roundToInt.c b/deps/SoftFloat-3e/source/f64_roundToInt.c deleted file mode 100644 index 54e7b0542767..000000000000 --- a/deps/SoftFloat-3e/source/f64_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t uiZ, lastBitMask, roundBitsMask; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x3FE ) { - if ( !(uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF64UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF64UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FE ) uiZ |= packToF64UI( 0, 0x3FF, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF64UI( 1, 0x3FF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF64UI( 0, 0x3FF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF64UI( 0, 0x3FF, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x433 <= exp ) { - if ( (exp == 0x7FF) && fracF64UI( uiA ) ) { - uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast64_t) 1<<(0x433 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF64UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_sqrt.c b/deps/SoftFloat-3e/source/f64_sqrt.c deleted file mode 100644 index f9f226b69766..000000000000 --- a/deps/SoftFloat-3e/source/f64_sqrt.c +++ /dev/null @@ -1,133 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_sqrt( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t sig32A, recipSqrt32, sig32Z; - uint_fast64_t rem; - uint32_t q; - uint_fast64_t sigZ, shiftedSigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FF)>>1) + 0x3FE; - expA &= 1; - sigA |= UINT64_C( 0x0010000000000000 ); - sig32A = sigA>>21; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sigA <<= 8; - sig32Z >>= 1; - } else { - sigA <<= 9; - } - rem = sigA - (uint_fast64_t) sig32Z * sig32Z; - q = ((uint32_t) (rem>>2) * (uint_fast64_t) recipSqrt32)>>32; - sigZ = ((uint_fast64_t) sig32Z<<32 | 1<<5) + ((uint_fast64_t) q<<3); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (sigZ & 0x1FF) < 0x22 ) { - sigZ &= ~(uint_fast64_t) 0x3F; - shiftedSigZ = sigZ>>6; - rem = (sigA<<52) - shiftedSigZ * shiftedSigZ; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - --sigZ; - } else { - if ( rem ) sigZ |= 1; - } - } - return softfloat_roundPackToF64( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_sub.c b/deps/SoftFloat-3e/source/f64_sub.c deleted file mode 100644 index b5ccb882bbd5..000000000000 --- a/deps/SoftFloat-3e/source/f64_sub.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_sub( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsF64( uiA, uiB, signA ); - } else { - return softfloat_addMagsF64( uiA, uiB, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF64 : softfloat_addMagsF64; - return (*magsFuncPtr)( uiA, uiB, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_extF80.c b/deps/SoftFloat-3e/source/f64_to_extF80.c deleted file mode 100644 index 2799d9b0709a..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f64_to_extF80( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp16_sig64 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); - uiZ0 = (frac | UINT64_C( 0x0010000000000000 ))<<11; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_extF80M.c b/deps/SoftFloat-3e/source/f64_to_extF80M.c deleted file mode 100644 index a2e67e46fcff..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f64_to_extF80( a ); - -} - -#else - -void f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui64_f64 uA; - uint64_t uiA; - bool sign; - int_fast16_t exp; - uint64_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint64_t uiZ0; - struct exp16_sig64 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); - uiZ0 = UINT64_C( 0x8000000000000000 ) | frac<<11; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f64_to_f128.c b/deps/SoftFloat-3e/source/f64_to_f128.c deleted file mode 100644 index 60af3b0be1aa..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f128.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f64_to_f128( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp16_sig64 normExpSig; - struct uint128 frac128; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac128 = softfloat_shortShiftLeft128( 0, frac, 60 ); - uiZ.v64 = packToF128UI64( sign, exp + 0x3C00, frac128.v64 ); - uiZ.v0 = frac128.v0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_f128M.c b/deps/SoftFloat-3e/source/f64_to_f128M.c deleted file mode 100644 index fbc451537397..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f128M.c +++ /dev/null @@ -1,117 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f64_to_f128M( float64_t a, float128_t *zPtr ) -{ - - *zPtr = f64_to_f128( a ); - -} - -#else - -void f64_to_f128M( float64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui64_f64 uA; - uint64_t uiA; - bool sign; - int_fast16_t exp; - uint64_t frac; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp16_sig64 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 0 )] = 0; - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 1 )] = (uint32_t) frac<<28; - frac >>= 4; - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp + 0x3C00, frac>>32 ); - zWPtr[indexWord( 4, 2 )] = frac; - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f64_to_f16.c b/deps/SoftFloat-3e/source/f64_to_f16.c deleted file mode 100644 index 121e3062a041..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f16.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f64_to_f16( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = softfloat_shortShiftRightJam64( frac, 38 ); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF16( sign, exp - 0x3F1, frac16 | 0x4000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_f32.c b/deps/SoftFloat-3e/source/f64_to_f32.c deleted file mode 100644 index a18106556da3..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f32.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f64_to_f32( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - uint_fast32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac, 22 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF32( sign, exp - 0x381, frac32 | 0x40000000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i32.c b/deps/SoftFloat-3e/source/f64_to_i32.c deleted file mode 100644 index 8d9785b0bc62..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i32.c +++ /dev/null @@ -1,82 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FF) && sig ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x427 - exp; - if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c deleted file mode 100644 index 8b7a91f1c068..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( shiftDist < 22 ) { - if ( - sign && (exp == 0x41E) && (sig < UINT64_C( 0x0000000000200000 )) - ) { - if ( exact && sig ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig>>shiftDist; - if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f64_to_i64( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint64_extra sigExtra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x433 - exp; -#ifdef SOFTFLOAT_FAST_INT64 - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sigExtra.v = sig<<-shiftDist; - sigExtra.extra = 0; - } else { - sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - } - return - softfloat_roundToI64( - sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sig <<= -shiftDist; - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - } else { - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - } - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && fracF64UI( uiA ) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c deleted file mode 100644 index 56c6a101016e..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -10 ) { - if ( uiA == packToF64UI( 1, 0x43E, 0 ) ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig<<-shiftDist; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig>>shiftDist; - if ( exact && (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FF) && sig ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x427 - exp; - if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c deleted file mode 100644 index 6e3d14e8f338..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f64_to_ui32_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( sign || (shiftDist < 21) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - z = sig>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f64_to_ui64( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint64_extra sigExtra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x433 - exp; -#ifdef SOFTFLOAT_FAST_INT64 - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sigExtra.v = sig<<-shiftDist; - sigExtra.extra = 0; - } else { - sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - } - return - softfloat_roundToUI64( - sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sig <<= -shiftDist; - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - } else { - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - } - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && fracF64UI( uiA ) ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c deleted file mode 100644 index 87eb0d05cb3b..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f64_to_ui64_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( sign ) goto invalid; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - z = (sig | UINT64_C( 0x0010000000000000 ))<<-shiftDist; - } else { - sig |= UINT64_C( 0x0010000000000000 ); - z = sig>>shiftDist; - if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_extF80.c b/deps/SoftFloat-3e/source/i32_to_extF80.c deleted file mode 100644 index 8036fa9f1186..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_extF80.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t i32_to_extF80( int32_t a ) -{ - uint_fast16_t uiZ64; - uint_fast32_t absA; - bool sign; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - absA = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ); - uiZ64 = packToExtF80UI64( sign, 0x401E - shiftDist ); - absA <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = (uint_fast64_t) absA<<32; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_extF80M.c b/deps/SoftFloat-3e/source/i32_to_extF80M.c deleted file mode 100644 index 6d5431c1c19c..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_extF80M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = i32_to_extF80( a ); - -} - -#else - -void i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - bool sign; - uint32_t absA; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint32_t) a : (uint32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ); - uiZ64 = packToExtF80UI64( sign, 0x401E - shiftDist ); - sigZ = (uint64_t) (absA<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i32_to_f128.c b/deps/SoftFloat-3e/source/i32_to_f128.c deleted file mode 100644 index a7d55cba429a..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f128.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t i32_to_f128( int32_t a ) -{ - uint_fast64_t uiZ64; - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui128_f128 uZ; - - uiZ64 = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 17; - uiZ64 = - packToF128UI64( - sign, 0x402E - shiftDist, (uint_fast64_t) absA< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i32_to_f128M( int32_t a, float128_t *zPtr ) -{ - - *zPtr = i32_to_f128( a ); - -} - -#else - -void i32_to_f128M( int32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - uint32_t uiZ96, uiZ64; - bool sign; - uint32_t absA; - int_fast8_t shiftDist; - uint64_t normAbsA; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint32_t) a : (uint32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 17; - normAbsA = (uint64_t) absA<>32 ); - uiZ64 = normAbsA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i32_to_f16.c b/deps/SoftFloat-3e/source/i32_to_f16.c deleted file mode 100644 index d3117248a233..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f16.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t i32_to_f16( int32_t a ) -{ - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) - 21; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - sign, 0x18 - shiftDist, (uint_fast16_t) absA<>(-shiftDist) - | ((uint32_t) (absA<<(shiftDist & 31)) != 0) - : (uint_fast16_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t i32_to_f32( int32_t a ) -{ - bool sign; - union ui32_f32 uZ; - uint_fast32_t absA; - - sign = (a < 0); - if ( ! (a & 0x7FFFFFFF) ) { - uZ.ui = sign ? packToF32UI( 1, 0x9E, 0 ) : 0; - return uZ.f; - } - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - return softfloat_normRoundPackToF32( sign, 0x9C, absA ); - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_f64.c b/deps/SoftFloat-3e/source/i32_to_f64.c deleted file mode 100644 index 24feda542d24..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f64.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t i32_to_f64( int32_t a ) -{ - uint_fast64_t uiZ; - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - if ( ! a ) { - uiZ = 0; - } else { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 21; - uiZ = - packToF64UI( - sign, 0x432 - shiftDist, (uint_fast64_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t i64_to_extF80( int64_t a ) -{ - uint_fast16_t uiZ64; - uint_fast64_t absA; - bool sign; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - absA = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ); - uiZ64 = packToExtF80UI64( sign, 0x403E - shiftDist ); - absA <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = absA; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i64_to_extF80M.c b/deps/SoftFloat-3e/source/i64_to_extF80M.c deleted file mode 100644 index 4838dde6dbbb..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_extF80M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = i64_to_extF80( a ); - -} - -#else - -void i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - bool sign; - uint64_t absA; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint64_t) a : (uint64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ); - uiZ64 = packToExtF80UI64( sign, 0x403E - shiftDist ); - sigZ = absA<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i64_to_f128.c b/deps/SoftFloat-3e/source/i64_to_f128.c deleted file mode 100644 index fcb0179392c5..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f128.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t i64_to_f128( int64_t a ) -{ - uint_fast64_t uiZ64, uiZ0; - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - struct uint128 zSig; - union ui128_f128 uZ; - - if ( ! a ) { - uiZ64 = 0; - uiZ0 = 0; - } else { - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) + 49; - if ( 64 <= shiftDist ) { - zSig.v64 = absA<<(shiftDist - 64); - zSig.v0 = 0; - } else { - zSig = softfloat_shortShiftLeft128( 0, absA, shiftDist ); - } - uiZ64 = packToF128UI64( sign, 0x406E - shiftDist, zSig.v64 ); - uiZ0 = zSig.v0; - } - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i64_to_f128M.c b/deps/SoftFloat-3e/source/i64_to_f128M.c deleted file mode 100644 index 0a04eb8d072b..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f128M.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i64_to_f128M( int64_t a, float128_t *zPtr ) -{ - - *zPtr = i64_to_f128( a ); - -} - -#else - -void i64_to_f128M( int64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - uint32_t uiZ96, uiZ64; - bool sign; - uint64_t absA; - uint_fast8_t shiftDist; - uint32_t *ptr; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint64_t) a : (uint64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) + 17; - if ( shiftDist < 32 ) { - ptr = zWPtr + indexMultiwordHi( 4, 3 ); - ptr[indexWord( 3, 2 )] = 0; - ptr[indexWord( 3, 1 )] = absA>>32; - ptr[indexWord( 3, 0 )] = absA; - softfloat_shortShiftLeft96M( ptr, shiftDist, ptr ); - ptr[indexWordHi( 3 )] = - packToF128UI96( - sign, 0x404E - shiftDist, ptr[indexWordHi( 3 )] ); - return; - } - absA <<= shiftDist - 32; - uiZ96 = packToF128UI96( sign, 0x404E - shiftDist, absA>>32 ); - uiZ64 = absA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i64_to_f16.c b/deps/SoftFloat-3e/source/i64_to_f16.c deleted file mode 100644 index cef7b6133a03..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f16.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t i64_to_f16( int64_t a ) -{ - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) - 53; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - sign, 0x18 - shiftDist, (uint_fast16_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t i64_to_f32( int64_t a ) -{ - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - union ui32_f32 u; - uint_fast32_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) - 40; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF32UI( - sign, 0x95 - shiftDist, (uint_fast32_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t i64_to_f64( int64_t a ) -{ - bool sign; - union ui64_f64 uZ; - uint_fast64_t absA; - - sign = (a < 0); - if ( ! (a & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { - uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0; - return uZ.f; - } - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - return softfloat_normRoundPackToF64( sign, 0x43C, absA ); - -} - diff --git a/deps/SoftFloat-3e/source/include/internals.h b/deps/SoftFloat-3e/source/include/internals.h deleted file mode 100644 index 020b3402f59f..000000000000 --- a/deps/SoftFloat-3e/source/include/internals.h +++ /dev/null @@ -1,278 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef internals_h -#define internals_h 1 - -#include -#include -#include "primitives.h" -#include "softfloat_types.h" - -union ui16_f16 { uint16_t ui; float16_t f; }; -union ui32_f32 { uint32_t ui; float32_t f; }; -union ui64_f64 { uint64_t ui; float64_t f; }; - -#ifdef SOFTFLOAT_FAST_INT64 -union extF80M_extF80 { struct extFloat80M fM; extFloat80_t f; }; -union ui128_f128 { struct uint128 ui; float128_t f; }; -#endif - -enum { - softfloat_mulAdd_subC = 1, - softfloat_mulAdd_subProd = 2 -}; - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_roundToUI32( bool, uint_fast64_t, uint_fast8_t, bool ); - -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast64_t - softfloat_roundToUI64( - bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); -#else -uint_fast64_t softfloat_roundMToUI64( bool, uint32_t *, uint_fast8_t, bool ); -#endif - -int_fast32_t softfloat_roundToI32( bool, uint_fast64_t, uint_fast8_t, bool ); - -#ifdef SOFTFLOAT_FAST_INT64 -int_fast64_t - softfloat_roundToI64( - bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); -#else -int_fast64_t softfloat_roundMToI64( bool, uint32_t *, uint_fast8_t, bool ); -#endif - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) -#define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) -#define fracF16UI( a ) ((a) & 0x03FF) -#define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) - -#define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF)) - -struct exp8_sig16 { int_fast8_t exp; uint_fast16_t sig; }; -struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t ); - -float16_t softfloat_roundPackToF16( bool, int_fast16_t, uint_fast16_t ); -float16_t softfloat_normRoundPackToF16( bool, int_fast16_t, uint_fast16_t ); - -float16_t softfloat_addMagsF16( uint_fast16_t, uint_fast16_t ); -float16_t softfloat_subMagsF16( uint_fast16_t, uint_fast16_t ); -float16_t - softfloat_mulAddF16( - uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF32UI( a ) ((bool) ((uint32_t) (a)>>31)) -#define expF32UI( a ) ((int_fast16_t) ((a)>>23) & 0xFF) -#define fracF32UI( a ) ((a) & 0x007FFFFF) -#define packToF32UI( sign, exp, sig ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig)) - -#define isNaNF32UI( a ) (((~(a) & 0x7F800000) == 0) && ((a) & 0x007FFFFF)) - -struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; }; -struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t ); - -float32_t softfloat_roundPackToF32( bool, int_fast16_t, uint_fast32_t ); -float32_t softfloat_normRoundPackToF32( bool, int_fast16_t, uint_fast32_t ); - -float32_t softfloat_addMagsF32( uint_fast32_t, uint_fast32_t ); -float32_t softfloat_subMagsF32( uint_fast32_t, uint_fast32_t ); -float32_t - softfloat_mulAddF32( - uint_fast32_t, uint_fast32_t, uint_fast32_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF64UI( a ) ((bool) ((uint64_t) (a)>>63)) -#define expF64UI( a ) ((int_fast16_t) ((a)>>52) & 0x7FF) -#define fracF64UI( a ) ((a) & UINT64_C( 0x000FFFFFFFFFFFFF )) -#define packToF64UI( sign, exp, sig ) ((uint64_t) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<52) + (sig))) - -#define isNaNF64UI( a ) (((~(a) & UINT64_C( 0x7FF0000000000000 )) == 0) && ((a) & UINT64_C( 0x000FFFFFFFFFFFFF ))) - -struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; }; -struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t ); - -float64_t softfloat_roundPackToF64( bool, int_fast16_t, uint_fast64_t ); -float64_t softfloat_normRoundPackToF64( bool, int_fast16_t, uint_fast64_t ); - -float64_t softfloat_addMagsF64( uint_fast64_t, uint_fast64_t, bool ); -float64_t softfloat_subMagsF64( uint_fast64_t, uint_fast64_t, bool ); -float64_t - softfloat_mulAddF64( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signExtF80UI64( a64 ) ((bool) ((uint16_t) (a64)>>15)) -#define expExtF80UI64( a64 ) ((a64) & 0x7FFF) -#define packToExtF80UI64( sign, exp ) ((uint_fast16_t) (sign)<<15 | (exp)) - -#define isNaNExtF80UI( a64, a0 ) ((((a64) & 0x7FFF) == 0x7FFF) && ((a0) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ - -struct exp32_sig64 { int_fast32_t exp; uint64_t sig; }; -struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t ); - -extFloat80_t - softfloat_roundPackToExtF80( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); -extFloat80_t - softfloat_normRoundPackToExtF80( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); - -extFloat80_t - softfloat_addMagsExtF80( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -extFloat80_t - softfloat_subMagsExtF80( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF128UI64( a64 ) ((bool) ((uint64_t) (a64)>>63)) -#define expF128UI64( a64 ) ((int_fast32_t) ((a64)>>48) & 0x7FFF) -#define fracF128UI64( a64 ) ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )) -#define packToF128UI64( sign, exp, sig64 ) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<48) + (sig64)) - -#define isNaNF128UI( a64, a0 ) (((~(a64) & UINT64_C( 0x7FFF000000000000 )) == 0) && (a0 || ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )))) - -struct exp32_sig128 { int_fast32_t exp; struct uint128 sig; }; -struct exp32_sig128 - softfloat_normSubnormalF128Sig( uint_fast64_t, uint_fast64_t ); - -float128_t - softfloat_roundPackToF128( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast64_t ); -float128_t - softfloat_normRoundPackToF128( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t ); - -float128_t - softfloat_addMagsF128( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -float128_t - softfloat_subMagsF128( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -float128_t - softfloat_mulAddF128( - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast8_t - ); - -#else - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ - -bool - softfloat_tryPropagateNaNExtF80M( - const struct extFloat80M *, - const struct extFloat80M *, - struct extFloat80M * - ); -void softfloat_invalidExtF80M( struct extFloat80M * ); - -int softfloat_normExtF80SigM( uint64_t * ); - -void - softfloat_roundPackMToExtF80M( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); -void - softfloat_normRoundPackMToExtF80M( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); - -void - softfloat_addExtF80M( - const struct extFloat80M *, - const struct extFloat80M *, - struct extFloat80M *, - bool - ); - -int - softfloat_compareNonnormExtF80M( - const struct extFloat80M *, const struct extFloat80M * ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF128UI96( a96 ) ((bool) ((uint32_t) (a96)>>31)) -#define expF128UI96( a96 ) ((int32_t) ((a96)>>16) & 0x7FFF) -#define fracF128UI96( a96 ) ((a96) & 0x0000FFFF) -#define packToF128UI96( sign, exp, sig96 ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<16) + (sig96)) - -bool softfloat_isNaNF128M( const uint32_t * ); - -bool - softfloat_tryPropagateNaNF128M( - const uint32_t *, const uint32_t *, uint32_t * ); -void softfloat_invalidF128M( uint32_t * ); - -int softfloat_shiftNormSigF128M( const uint32_t *, uint_fast8_t, uint32_t * ); - -void softfloat_roundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); -void softfloat_normRoundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); - -void - softfloat_addF128M( const uint32_t *, const uint32_t *, uint32_t *, bool ); -void - softfloat_mulAddF128M( - const uint32_t *, - const uint32_t *, - const uint32_t *, - uint32_t *, - uint_fast8_t - ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/opts-GCC.h b/deps/SoftFloat-3e/source/include/opts-GCC.h deleted file mode 100644 index 18c1523e9205..000000000000 --- a/deps/SoftFloat-3e/source/include/opts-GCC.h +++ /dev/null @@ -1,114 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2017 The Regents of the University of California. All rights -reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef opts_GCC_h -#define opts_GCC_h 1 - -#ifdef INLINE - -#include -#include "primitiveTypes.h" - -#ifdef SOFTFLOAT_BUILTIN_CLZ - -INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) - { return a ? __builtin_clz( a ) - 16 : 16; } -#define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 - -INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) - { return a ? __builtin_clz( a ) : 32; } -#define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 - -INLINE uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ) - { return a ? __builtin_clzll( a ) : 64; } -#define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 - -#endif - -#ifdef SOFTFLOAT_INTRINSIC_INT128 - -INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = (unsigned __int128) a * ((uint_fast64_t) b<<32); - return uZ.s; -} -#define softfloat_mul64ByShifted32To128 softfloat_mul64ByShifted32To128 - -INLINE struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = (unsigned __int128) a * b; - return uZ.s; -} -#define softfloat_mul64To128 softfloat_mul64To128 - -INLINE -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = ((unsigned __int128) a64<<64 | a0) * b; - return uZ.s; -} -#define softfloat_mul128By32 softfloat_mul128By32 - -INLINE -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ) -{ - unsigned __int128 z0, mid1, mid, z128; - z0 = (unsigned __int128) a0 * b0; - mid1 = (unsigned __int128) a64 * b0; - mid = mid1 + (unsigned __int128) a0 * b64; - z128 = (unsigned __int128) a64 * b64; - z128 += (unsigned __int128) (mid < mid1)<<64 | mid>>64; - mid <<= 64; - z0 += mid; - z128 += (z0 < mid); - zPtr[indexWord( 4, 0 )] = z0; - zPtr[indexWord( 4, 1 )] = z0>>64; - zPtr[indexWord( 4, 2 )] = z128; - zPtr[indexWord( 4, 3 )] = z128>>64; -} -#define softfloat_mul128To256M softfloat_mul128To256M - -#endif - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/primitiveTypes.h b/deps/SoftFloat-3e/source/include/primitiveTypes.h deleted file mode 100644 index 4407f5e7cb06..000000000000 --- a/deps/SoftFloat-3e/source/include/primitiveTypes.h +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef primitiveTypes_h -#define primitiveTypes_h 1 - -#include "platform.h" -#include - -#ifdef SOFTFLOAT_FAST_INT64 - -#ifdef LITTLEENDIAN -struct uint128 { uint64_t v0, v64; }; -struct uint64_extra { uint64_t extra, v; }; -struct uint128_extra { uint64_t extra; struct uint128 v; }; -#else -struct uint128 { uint64_t v64, v0; }; -struct uint64_extra { uint64_t v, extra; }; -struct uint128_extra { struct uint128 v; uint64_t extra; }; -#endif - -#endif - -/*---------------------------------------------------------------------------- -| These macros are used to isolate the differences in word order between big- -| endian and little-endian platforms. -*----------------------------------------------------------------------------*/ -#ifdef LITTLEENDIAN -#define wordIncr 1 -#define indexWord( total, n ) (n) -#define indexWordHi( total ) ((total) - 1) -#define indexWordLo( total ) 0 -#define indexMultiword( total, m, n ) (n) -#define indexMultiwordHi( total, n ) ((total) - (n)) -#define indexMultiwordLo( total, n ) 0 -#define indexMultiwordHiBut( total, n ) (n) -#define indexMultiwordLoBut( total, n ) 0 -#define INIT_UINTM4( v3, v2, v1, v0 ) { v0, v1, v2, v3 } -#else -#define wordIncr -1 -#define indexWord( total, n ) ((total) - 1 - (n)) -#define indexWordHi( total ) 0 -#define indexWordLo( total ) ((total) - 1) -#define indexMultiword( total, m, n ) ((total) - 1 - (m)) -#define indexMultiwordHi( total, n ) 0 -#define indexMultiwordLo( total, n ) ((total) - (n)) -#define indexMultiwordHiBut( total, n ) 0 -#define indexMultiwordLoBut( total, n ) (n) -#define INIT_UINTM4( v3, v2, v1, v0 ) { v3, v2, v1, v0 } -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/primitives.h b/deps/SoftFloat-3e/source/include/primitives.h deleted file mode 100644 index 863ab45b57ca..000000000000 --- a/deps/SoftFloat-3e/source/include/primitives.h +++ /dev/null @@ -1,1160 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef primitives_h -#define primitives_h 1 - -#include -#include -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam64 -/*---------------------------------------------------------------------------- -| Shifts 'a' right by the number of bits given in 'dist', which must be in -| the range 1 to 63. If any nonzero bits are shifted off, they are "jammed" -| into the least-significant bit of the shifted value by setting the least- -| significant bit to 1. This shifted-and-jammed value is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) - { return a>>dist | ((a & (((uint_fast64_t) 1<>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); -} -#else -uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam64 -/*---------------------------------------------------------------------------- -| Shifts 'a' right by the number of bits given in 'dist', which must not -| be zero. If any nonzero bits are shifted off, they are "jammed" into the -| least-significant bit of the shifted value by setting the least-significant -| bit to 1. This shifted-and-jammed value is returned. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than 64, the result will be either 0 or 1, depending on whether 'a' -| is zero or nonzero. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) -{ - return - (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); -} -#else -uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ); -#endif -#endif - -/*---------------------------------------------------------------------------- -| A constant table that translates an 8-bit unsigned integer (the array index) -| into the number of leading 0 bits before the most-significant 1 of that -| integer. For integer zero (index 0), the corresponding table element is 8. -*----------------------------------------------------------------------------*/ -extern const uint_least8_t softfloat_countLeadingZeros8[256]; - -#ifndef softfloat_countLeadingZeros16 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 16 is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) -{ - uint_fast8_t count = 8; - if ( 0x100 <= a ) { - count = 0; - a >>= 8; - } - count += softfloat_countLeadingZeros8[a]; - return count; -} -#else -uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ); -#endif -#endif - -#ifndef softfloat_countLeadingZeros32 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 32 is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) -{ - uint_fast8_t count = 0; - if ( a < 0x10000 ) { - count = 16; - a <<= 16; - } - if ( a < 0x1000000 ) { - count += 8; - a <<= 8; - } - count += softfloat_countLeadingZeros8[a>>24]; - return count; -} -#else -uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ); -#endif -#endif - -#ifndef softfloat_countLeadingZeros64 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 64 is returned. -*----------------------------------------------------------------------------*/ -uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ); -#endif - -extern const uint16_t softfloat_approxRecip_1k0s[16]; -extern const uint16_t softfloat_approxRecip_1k1s[16]; - -#ifndef softfloat_approxRecip32_1 -/*---------------------------------------------------------------------------- -| Returns an approximation to the reciprocal of the number represented by 'a', -| where 'a' is interpreted as an unsigned fixed-point number with one integer -| bit and 31 fraction bits. The 'a' input must be "normalized", meaning that -| its most-significant bit (bit 31) must be 1. Thus, if A is the value of -| the fixed-point interpretation of 'a', then 1 <= A < 2. The returned value -| is interpreted as a pure unsigned fraction, having no integer bits and 32 -| fraction bits. The approximation returned is never greater than the true -| reciprocal 1/A, and it differs from the true reciprocal by at most 2.006 ulp -| (units in the last place). -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_DIV64TO32 -#define softfloat_approxRecip32_1( a ) ((uint32_t) (UINT64_C( 0x7FFFFFFFFFFFFFFF ) / (uint32_t) (a))) -#else -uint32_t softfloat_approxRecip32_1( uint32_t a ); -#endif -#endif - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[16]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[16]; - -#ifndef softfloat_approxRecipSqrt32_1 -/*---------------------------------------------------------------------------- -| Returns an approximation to the reciprocal of the square root of the number -| represented by 'a', where 'a' is interpreted as an unsigned fixed-point -| number either with one integer bit and 31 fraction bits or with two integer -| bits and 30 fraction bits. The format of 'a' is determined by 'oddExpA', -| which must be either 0 or 1. If 'oddExpA' is 1, 'a' is interpreted as -| having one integer bit, and if 'oddExpA' is 0, 'a' is interpreted as having -| two integer bits. The 'a' input must be "normalized", meaning that its -| most-significant bit (bit 31) must be 1. Thus, if A is the value of the -| fixed-point interpretation of 'a', it follows that 1 <= A < 2 when 'oddExpA' -| is 1, and 2 <= A < 4 when 'oddExpA' is 0. -| The returned value is interpreted as a pure unsigned fraction, having -| no integer bits and 32 fraction bits. The approximation returned is never -| greater than the true reciprocal 1/sqrt(A), and it differs from the true -| reciprocal by at most 2.06 ulp (units in the last place). The approximation -| returned is also always within the range 0.5 to 1; thus, the most- -| significant bit of the result is always set. -*----------------------------------------------------------------------------*/ -uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ); -#endif - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -#ifndef softfloat_eq128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is equal to the 128-bit unsigned integer formed by concatenating -| 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) -INLINE -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 == b64) && (a0 == b0); } -#else -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_le128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is less than or equal to the 128-bit unsigned integer formed by -| concatenating 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); } -#else -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_lt128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is less than the 128-bit unsigned integer formed by concatenating -| 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 < b64) || ((a64 == b64) && (a0 < b0)); } -#else -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_shortShiftLeft128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' left by the -| number of bits given in 'dist', which must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - z.v64 = a64<>(-dist & 63); - z.v0 = a0<>dist; - z.v0 = a64<<(-dist & 63) | a0>>dist; - return z; -} -#else -struct uint128 - softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam64Extra -/*---------------------------------------------------------------------------- -| This function is the same as 'softfloat_shiftRightJam64Extra' (below), -| except that 'dist' must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ) -{ - struct uint64_extra z; - z.v = a>>dist; - z.extra = a<<(-dist & 63) | (extra != 0); - return z; -} -#else -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the -| number of bits given in 'dist', which must be in the range 1 to 63. If any -| nonzero bits are shifted off, they are "jammed" into the least-significant -| bit of the shifted value by setting the least-significant bit to 1. This -| shifted-and-jammed value is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - uint_fast8_t negDist = -dist; - struct uint128 z; - z.v64 = a64>>dist; - z.v0 = - a64<<(negDist & 63) | a0>>dist - | ((uint64_t) (a0<<(negDist & 63)) != 0); - return z; -} -#else -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam128Extra -/*---------------------------------------------------------------------------- -| This function is the same as 'softfloat_shiftRightJam128Extra' (below), -| except that 'dist' must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) -{ - uint_fast8_t negDist = -dist; - struct uint128_extra z; - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(negDist & 63) | a0>>dist; - z.extra = a0<<(negDist & 63) | (extra != 0); - return z; -} -#else -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam64Extra -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a' and 'extra' right by 64 -| _plus_ the number of bits given in 'dist', which must not be zero. This -| shifted value is at most 64 nonzero bits and is returned in the 'v' field -| of the 'struct uint64_extra' result. The 64-bit 'extra' field of the result -| contains a value formed as follows from the bits that were shifted off: The -| _last_ bit shifted off is the most-significant bit of the 'extra' field, and -| the other 63 bits of the 'extra' field are all zero if and only if _all_but_ -| _the_last_ bits shifted off were all zero. -| (This function makes more sense if 'a' and 'extra' are considered to form -| an unsigned fixed-point number with binary point between 'a' and 'extra'. -| This fixed-point value is shifted right by the number of bits given in -| 'dist', and the integer part of this shifted value is returned in the 'v' -| field of the result. The fractional part of the shifted value is modified -| as described above and returned in the 'extra' field of the result.) -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) -INLINE -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ) -{ - struct uint64_extra z; - if ( dist < 64 ) { - z.v = a>>dist; - z.extra = a<<(-dist & 63); - } else { - z.v = 0; - z.extra = (dist == 64) ? a : (a != 0); - } - z.extra |= (extra != 0); - return z; -} -#else -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the -| number of bits given in 'dist', which must not be zero. If any nonzero bits -| are shifted off, they are "jammed" into the least-significant bit of the -| shifted value by setting the least-significant bit to 1. This shifted-and- -| jammed value is returned. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than 128, the result will be either 0 or 1, depending on whether the -| original 128 bits are all zeros. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ); -#endif - -#ifndef softfloat_shiftRightJam128Extra -/*---------------------------------------------------------------------------- -| Shifts the 192 bits formed by concatenating 'a64', 'a0', and 'extra' right -| by 64 _plus_ the number of bits given in 'dist', which must not be zero. -| This shifted value is at most 128 nonzero bits and is returned in the 'v' -| field of the 'struct uint128_extra' result. The 64-bit 'extra' field of the -| result contains a value formed as follows from the bits that were shifted -| off: The _last_ bit shifted off is the most-significant bit of the 'extra' -| field, and the other 63 bits of the 'extra' field are all zero if and only -| if _all_but_the_last_ bits shifted off were all zero. -| (This function makes more sense if 'a64', 'a0', and 'extra' are considered -| to form an unsigned fixed-point number with binary point between 'a0' and -| 'extra'. This fixed-point value is shifted right by the number of bits -| given in 'dist', and the integer part of this shifted value is returned -| in the 'v' field of the result. The fractional part of the shifted value -| is modified as described above and returned in the 'extra' field of the -| result.) -*----------------------------------------------------------------------------*/ -struct uint128_extra - softfloat_shiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ); -#endif - -#ifndef softfloat_shiftRightJam256M -/*---------------------------------------------------------------------------- -| Shifts the 256-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', which must not be zero. If any nonzero bits are -| shifted off, they are "jammed" into the least-significant bit of the shifted -| value by setting the least-significant bit to 1. This shifted-and-jammed -| value is stored at the location pointed to by 'zPtr'. Each of 'aPtr' and -| 'zPtr' points to an array of four 64-bit elements that concatenate in the -| platform's normal endian order to form a 256-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' -| is greater than 256, the stored result will be either 0 or 1, depending on -| whether the original 256 bits are all zeros. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightJam256M( - const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ); -#endif - -#ifndef softfloat_add128 -/*---------------------------------------------------------------------------- -| Returns the sum of the 128-bit integer formed by concatenating 'a64' and -| 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. The -| addition is modulo 2^128, so any carry out is lost. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - z.v0 = a0 + b0; - z.v64 = a64 + b64 + (z.v0 < a0); - return z; -} -#else -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_add256M -/*---------------------------------------------------------------------------- -| Adds the two 256-bit integers pointed to by 'aPtr' and 'bPtr'. The addition -| is modulo 2^256, so any carry out is lost. The sum is stored at the -| location pointed to by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to -| an array of four 64-bit elements that concatenate in the platform's normal -| endian order to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_add256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); -#endif - -#ifndef softfloat_sub128 -/*---------------------------------------------------------------------------- -| Returns the difference of the 128-bit integer formed by concatenating 'a64' -| and 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. -| The subtraction is modulo 2^128, so any borrow out (carry out) is lost. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - z.v0 = a0 - b0; - z.v64 = a64 - b64; - z.v64 -= (a0 < b0); - return z; -} -#else -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_sub256M -/*---------------------------------------------------------------------------- -| Subtracts the 256-bit integer pointed to by 'bPtr' from the 256-bit integer -| pointed to by 'aPtr'. The addition is modulo 2^256, so any borrow out -| (carry out) is lost. The difference is stored at the location pointed to -| by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to an array of four -| 64-bit elements that concatenate in the platform's normal endian order to -| form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_sub256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); -#endif - -#ifndef softfloat_mul64ByShifted32To128 -/*---------------------------------------------------------------------------- -| Returns the 128-bit product of 'a', 'b', and 2^32. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - uint_fast64_t mid; - struct uint128 z; - mid = (uint_fast64_t) (uint32_t) a * b; - z.v0 = mid<<32; - z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); - return z; -} -#else -struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ); -#endif -#endif - -#ifndef softfloat_mul64To128 -/*---------------------------------------------------------------------------- -| Returns the 128-bit product of 'a' and 'b'. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ); -#endif - -#ifndef softfloat_mul128By32 -/*---------------------------------------------------------------------------- -| Returns the product of the 128-bit integer formed by concatenating 'a64' and -| 'a0', multiplied by 'b'. The multiplication is modulo 2^128; any overflow -| bits are discarded. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) -INLINE -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - struct uint128 z; - uint_fast64_t mid; - uint_fast32_t carry; - z.v0 = a0 * b; - mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; - carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); - z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); - return z; -} -#else -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ); -#endif -#endif - -#ifndef softfloat_mul128To256M -/*---------------------------------------------------------------------------- -| Multiplies the 128-bit unsigned integer formed by concatenating 'a64' and -| 'a0' by the 128-bit unsigned integer formed by concatenating 'b64' and -| 'b0'. The 256-bit product is stored at the location pointed to by 'zPtr'. -| Argument 'zPtr' points to an array of four 64-bit elements that concatenate -| in the platform's normal endian order to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ); -#endif - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -#ifndef softfloat_compare96M -/*---------------------------------------------------------------------------- -| Compares the two 96-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. -| Returns -1 if the first integer (A) is less than the second (B); returns 0 -| if the two integers are equal; and returns +1 if the first integer (A) -| is greater than the second (B). (The result is thus the signum of A - B.) -| Each of 'aPtr' and 'bPtr' points to an array of three 32-bit elements that -| concatenate in the platform's normal endian order to form a 96-bit integer. -*----------------------------------------------------------------------------*/ -int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ); -#endif - -#ifndef softfloat_compare128M -/*---------------------------------------------------------------------------- -| Compares the two 128-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. -| Returns -1 if the first integer (A) is less than the second (B); returns 0 -| if the two integers are equal; and returns +1 if the first integer (A) -| is greater than the second (B). (The result is thus the signum of A - B.) -| Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that -| concatenate in the platform's normal endian order to form a 128-bit integer. -*----------------------------------------------------------------------------*/ -int_fast8_t - softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ); -#endif - -#ifndef softfloat_shortShiftLeft64To96M -/*---------------------------------------------------------------------------- -| Extends 'a' to 96 bits and shifts the value left by the number of bits given -| in 'dist', which must be in the range 1 to 31. The result is stored at the -| location pointed to by 'zPtr'. Argument 'zPtr' points to an array of three -| 32-bit elements that concatenate in the platform's normal endian order to -| form a 96-bit integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) -{ - zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; - zPtr[indexWord( 3, 2 )] = a>>32; - zPtr[indexWord( 3, 1 )] = a; -} -#else -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ); -#endif -#endif - -#ifndef softfloat_shortShiftLeftM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. Any nonzero bits shifted off are lost. The -| shifted N-bit result is stored at the location pointed to by 'zPtr'. Each -| of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements -| that concatenate in the platform's normal endian order to form an N-bit -| integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shortShiftLeft96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft96M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftLeft128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft128M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftLeft160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft160M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeftM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. Any nonzero bits shifted off are lost. The shifted -| N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' -| and 'zPtr' points to a 'size_words'-long array of 32-bit elements that -| concatenate in the platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than N, the stored result will be 0. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftLeft96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft96M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeft128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft128M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeft160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft160M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRightM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. Any nonzero bits shifted off are lost. The -| shifted N-bit result is stored at the location pointed to by 'zPtr'. Each -| of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements -| that concatenate in the platform's normal endian order to form an N-bit -| integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shortShiftRight128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRight128M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRight160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRight160M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRightJamM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. If any nonzero bits are shifted off, they are -| "jammed" into the least-significant bit of the shifted value by setting the -| least-significant bit to 1. This shifted-and-jammed N-bit result is stored -| at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftRightJamM( - uint_fast8_t, const uint32_t *, uint_fast8_t, uint32_t * ); -#endif - -#ifndef softfloat_shortShiftRightJam160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightJamM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRightJam160M( aPtr, dist, zPtr ) softfloat_shortShiftRightJamM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. Any nonzero bits shifted off are lost. The shifted -| N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' -| and 'zPtr' points to a 'size_words'-long array of 32-bit elements that -| concatenate in the platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than N, the stored result will be 0. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftRight96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRight96M( aPtr, dist, zPtr ) softfloat_shiftRightM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJamM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. If any nonzero bits are shifted off, they are "jammed" -| into the least-significant bit of the shifted value by setting the least- -| significant bit to 1. This shifted-and-jammed N-bit result is stored -| at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' -| is greater than N, the stored result will be either 0 or 1, depending on -| whether the original N bits are all zeros. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftRightJam96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam96M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJam128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam128M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJam160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam160M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_addM -/*---------------------------------------------------------------------------- -| Adds the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = -| 'size_words' * 32. The addition is modulo 2^N, so any carry out is lost. -| The N-bit sum is stored at the location pointed to by 'zPtr'. Each of -| 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long array of 32-bit -| elements that concatenate in the platform's normal endian order to form an -| N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_addM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_add96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_add96M( aPtr, bPtr, zPtr ) softfloat_addM( 3, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_add128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_add128M( aPtr, bPtr, zPtr ) softfloat_addM( 4, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_add160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_add160M( aPtr, bPtr, zPtr ) softfloat_addM( 5, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_addCarryM -/*---------------------------------------------------------------------------- -| Adds the two N-bit unsigned integers pointed to by 'aPtr' and 'bPtr', where -| N = 'size_words' * 32, plus 'carry', which must be either 0 or 1. The N-bit -| sum (modulo 2^N) is stored at the location pointed to by 'zPtr', and any -| carry out is returned as the result. Each of 'aPtr', 'bPtr', and 'zPtr' -| points to a 'size_words'-long array of 32-bit elements that concatenate in -| the platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -uint_fast8_t - softfloat_addCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_addComplCarryM -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addCarryM', except that -| the value of the unsigned integer pointed to by 'bPtr' is bit-wise completed -| before the addition. -*----------------------------------------------------------------------------*/ -uint_fast8_t - softfloat_addComplCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_addComplCarry96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addComplCarryM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_addComplCarry96M( aPtr, bPtr, carry, zPtr ) softfloat_addComplCarryM( 3, aPtr, bPtr, carry, zPtr ) -#endif - -#ifndef softfloat_negXM -/*---------------------------------------------------------------------------- -| Replaces the N-bit unsigned integer pointed to by 'zPtr' by the -| 2s-complement of itself, where N = 'size_words' * 32. Argument 'zPtr' -| points to a 'size_words'-long array of 32-bit elements that concatenate in -| the platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ); -#endif - -#ifndef softfloat_negX96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_negX96M( zPtr ) softfloat_negXM( 3, zPtr ) -#endif - -#ifndef softfloat_negX128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_negX128M( zPtr ) softfloat_negXM( 4, zPtr ) -#endif - -#ifndef softfloat_negX160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_negX160M( zPtr ) softfloat_negXM( 5, zPtr ) -#endif - -#ifndef softfloat_negX256M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 8 (N = 256). -*----------------------------------------------------------------------------*/ -#define softfloat_negX256M( zPtr ) softfloat_negXM( 8, zPtr ) -#endif - -#ifndef softfloat_sub1XM -/*---------------------------------------------------------------------------- -| Subtracts 1 from the N-bit integer pointed to by 'zPtr', where N = -| 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry -| out) is lost. Argument 'zPtr' points to a 'size_words'-long array of 32-bit -| elements that concatenate in the platform's normal endian order to form an -| N-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ); -#endif - -#ifndef softfloat_sub1X96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_sub1X96M( zPtr ) softfloat_sub1XM( 3, zPtr ) -#endif - -#ifndef softfloat_sub1X160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_sub1X160M( zPtr ) softfloat_sub1XM( 5, zPtr ) -#endif - -#ifndef softfloat_subM -/*---------------------------------------------------------------------------- -| Subtracts the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = -| 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry -| out) is lost. The N-bit difference is stored at the location pointed to by -| 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long -| array of 32-bit elements that concatenate in the platform's normal endian -| order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_subM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_sub96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_sub96M( aPtr, bPtr, zPtr ) softfloat_subM( 3, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_sub128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_sub128M( aPtr, bPtr, zPtr ) softfloat_subM( 4, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_sub160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_sub160M( aPtr, bPtr, zPtr ) softfloat_subM( 5, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_mul64To128M -/*---------------------------------------------------------------------------- -| Multiplies 'a' and 'b' and stores the 128-bit product at the location -| pointed to by 'zPtr'. Argument 'zPtr' points to an array of four 32-bit -| elements that concatenate in the platform's normal endian order to form a -| 128-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ); -#endif - -#ifndef softfloat_mul128MTo256M -/*---------------------------------------------------------------------------- -| Multiplies the two 128-bit unsigned integers pointed to by 'aPtr' and -| 'bPtr', and stores the 256-bit product at the location pointed to by 'zPtr'. -| Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that -| concatenate in the platform's normal endian order to form a 128-bit integer. -| Argument 'zPtr' points to an array of eight 32-bit elements that concatenate -| to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_mul128MTo256M( - const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ); -#endif - -#ifndef softfloat_remStepMBy32 -/*---------------------------------------------------------------------------- -| Performs a "remainder reduction step" as follows: Arguments 'remPtr' and -| 'bPtr' both point to N-bit unsigned integers, where N = 'size_words' * 32. -| Defining R and B as the values of those integers, the expression (R<<'dist') -| - B * q is computed modulo 2^N, and the N-bit result is stored at the -| location pointed to by 'zPtr'. Each of 'remPtr', 'bPtr', and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_remStepMBy32( - uint_fast8_t size_words, - const uint32_t *remPtr, - uint_fast8_t dist, - const uint32_t *bPtr, - uint32_t q, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_remStep96MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep96MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 3, remPtr, dist, bPtr, q, zPtr ) -#endif - -#ifndef softfloat_remStep128MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep128MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 4, remPtr, dist, bPtr, q, zPtr ) -#endif - -#ifndef softfloat_remStep160MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep160MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 5, remPtr, dist, bPtr, q, zPtr ) -#endif - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/softfloat.h b/deps/SoftFloat-3e/source/include/softfloat.h deleted file mode 100644 index b33374cd6c8b..000000000000 --- a/deps/SoftFloat-3e/source/include/softfloat.h +++ /dev/null @@ -1,372 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - - -/*============================================================================ -| Note: If SoftFloat is made available as a general library for programs to -| use, it is strongly recommended that a platform-specific version of this -| header, "softfloat.h", be created that folds in "softfloat_types.h" and that -| eliminates all dependencies on compile-time macros. -*============================================================================*/ - - -#ifndef softfloat_h -#define softfloat_h 1 - -#include -#include -#include "softfloat_types.h" - -#ifndef THREAD_LOCAL -#define THREAD_LOCAL -#endif - -/*---------------------------------------------------------------------------- -| Software floating-point underflow tininess-detection mode. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess; -enum { - softfloat_tininess_beforeRounding = 0, - softfloat_tininess_afterRounding = 1 -}; - -/*---------------------------------------------------------------------------- -| Software floating-point rounding mode. (Mode "odd" is supported only if -| SoftFloat is compiled with macro 'SOFTFLOAT_ROUND_ODD' defined.) -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode; -enum { - softfloat_round_near_even = 0, - softfloat_round_minMag = 1, - softfloat_round_min = 2, - softfloat_round_max = 3, - softfloat_round_near_maxMag = 4, - softfloat_round_odd = 6 -}; - -/*---------------------------------------------------------------------------- -| Software floating-point exception flags. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; -enum { - softfloat_flag_inexact = 1, - softfloat_flag_underflow = 2, - softfloat_flag_overflow = 4, - softfloat_flag_infinite = 8, - softfloat_flag_invalid = 16 -}; - -/*---------------------------------------------------------------------------- -| Routine to raise any or all of the software floating-point exception flags. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t ); - -/*---------------------------------------------------------------------------- -| Integer-to-floating-point conversion routines. -*----------------------------------------------------------------------------*/ -float16_t ui32_to_f16( uint32_t ); -float32_t ui32_to_f32( uint32_t ); -float64_t ui32_to_f64( uint32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t ui32_to_extF80( uint32_t ); -float128_t ui32_to_f128( uint32_t ); -#endif -void ui32_to_extF80M( uint32_t, extFloat80_t * ); -void ui32_to_f128M( uint32_t, float128_t * ); -float16_t ui64_to_f16( uint64_t ); -float32_t ui64_to_f32( uint64_t ); -float64_t ui64_to_f64( uint64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t ui64_to_extF80( uint64_t ); -float128_t ui64_to_f128( uint64_t ); -#endif -void ui64_to_extF80M( uint64_t, extFloat80_t * ); -void ui64_to_f128M( uint64_t, float128_t * ); -float16_t i32_to_f16( int32_t ); -float32_t i32_to_f32( int32_t ); -float64_t i32_to_f64( int32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t i32_to_extF80( int32_t ); -float128_t i32_to_f128( int32_t ); -#endif -void i32_to_extF80M( int32_t, extFloat80_t * ); -void i32_to_f128M( int32_t, float128_t * ); -float16_t i64_to_f16( int64_t ); -float32_t i64_to_f32( int64_t ); -float64_t i64_to_f64( int64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t i64_to_extF80( int64_t ); -float128_t i64_to_f128( int64_t ); -#endif -void i64_to_extF80M( int64_t, extFloat80_t * ); -void i64_to_f128M( int64_t, float128_t * ); - -/*---------------------------------------------------------------------------- -| 16-bit (half-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f16_to_ui32( float16_t, uint_fast8_t, bool ); -uint_fast64_t f16_to_ui64( float16_t, uint_fast8_t, bool ); -int_fast32_t f16_to_i32( float16_t, uint_fast8_t, bool ); -int_fast64_t f16_to_i64( float16_t, uint_fast8_t, bool ); -uint_fast32_t f16_to_ui32_r_minMag( float16_t, bool ); -uint_fast64_t f16_to_ui64_r_minMag( float16_t, bool ); -int_fast32_t f16_to_i32_r_minMag( float16_t, bool ); -int_fast64_t f16_to_i64_r_minMag( float16_t, bool ); -float32_t f16_to_f32( float16_t ); -float64_t f16_to_f64( float16_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f16_to_extF80( float16_t ); -float128_t f16_to_f128( float16_t ); -#endif -void f16_to_extF80M( float16_t, extFloat80_t * ); -void f16_to_f128M( float16_t, float128_t * ); -float16_t f16_roundToInt( float16_t, uint_fast8_t, bool ); -float16_t f16_add( float16_t, float16_t ); -float16_t f16_sub( float16_t, float16_t ); -float16_t f16_mul( float16_t, float16_t ); -float16_t f16_mulAdd( float16_t, float16_t, float16_t ); -float16_t f16_div( float16_t, float16_t ); -float16_t f16_rem( float16_t, float16_t ); -float16_t f16_sqrt( float16_t ); -bool f16_eq( float16_t, float16_t ); -bool f16_le( float16_t, float16_t ); -bool f16_lt( float16_t, float16_t ); -bool f16_eq_signaling( float16_t, float16_t ); -bool f16_le_quiet( float16_t, float16_t ); -bool f16_lt_quiet( float16_t, float16_t ); -bool f16_isSignalingNaN( float16_t ); - -/*---------------------------------------------------------------------------- -| 32-bit (single-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f32_to_ui32( float32_t, uint_fast8_t, bool ); -uint_fast64_t f32_to_ui64( float32_t, uint_fast8_t, bool ); -int_fast32_t f32_to_i32( float32_t, uint_fast8_t, bool ); -int_fast64_t f32_to_i64( float32_t, uint_fast8_t, bool ); -uint_fast32_t f32_to_ui32_r_minMag( float32_t, bool ); -uint_fast64_t f32_to_ui64_r_minMag( float32_t, bool ); -int_fast32_t f32_to_i32_r_minMag( float32_t, bool ); -int_fast64_t f32_to_i64_r_minMag( float32_t, bool ); -float16_t f32_to_f16( float32_t ); -float64_t f32_to_f64( float32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f32_to_extF80( float32_t ); -float128_t f32_to_f128( float32_t ); -#endif -void f32_to_extF80M( float32_t, extFloat80_t * ); -void f32_to_f128M( float32_t, float128_t * ); -float32_t f32_roundToInt( float32_t, uint_fast8_t, bool ); -float32_t f32_add( float32_t, float32_t ); -float32_t f32_sub( float32_t, float32_t ); -float32_t f32_mul( float32_t, float32_t ); -float32_t f32_mulAdd( float32_t, float32_t, float32_t ); -float32_t f32_div( float32_t, float32_t ); -float32_t f32_rem( float32_t, float32_t ); -float32_t f32_sqrt( float32_t ); -bool f32_eq( float32_t, float32_t ); -bool f32_le( float32_t, float32_t ); -bool f32_lt( float32_t, float32_t ); -bool f32_eq_signaling( float32_t, float32_t ); -bool f32_le_quiet( float32_t, float32_t ); -bool f32_lt_quiet( float32_t, float32_t ); -bool f32_isSignalingNaN( float32_t ); - -/*---------------------------------------------------------------------------- -| 64-bit (double-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f64_to_ui32( float64_t, uint_fast8_t, bool ); -uint_fast64_t f64_to_ui64( float64_t, uint_fast8_t, bool ); -int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool ); -int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bool ); -uint_fast32_t f64_to_ui32_r_minMag( float64_t, bool ); -uint_fast64_t f64_to_ui64_r_minMag( float64_t, bool ); -int_fast32_t f64_to_i32_r_minMag( float64_t, bool ); -int_fast64_t f64_to_i64_r_minMag( float64_t, bool ); -float16_t f64_to_f16( float64_t ); -float32_t f64_to_f32( float64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f64_to_extF80( float64_t ); -float128_t f64_to_f128( float64_t ); -#endif -void f64_to_extF80M( float64_t, extFloat80_t * ); -void f64_to_f128M( float64_t, float128_t * ); -float64_t f64_roundToInt( float64_t, uint_fast8_t, bool ); -float64_t f64_add( float64_t, float64_t ); -float64_t f64_sub( float64_t, float64_t ); -float64_t f64_mul( float64_t, float64_t ); -float64_t f64_mulAdd( float64_t, float64_t, float64_t ); -float64_t f64_div( float64_t, float64_t ); -float64_t f64_rem( float64_t, float64_t ); -float64_t f64_sqrt( float64_t ); -bool f64_eq( float64_t, float64_t ); -bool f64_le( float64_t, float64_t ); -bool f64_lt( float64_t, float64_t ); -bool f64_eq_signaling( float64_t, float64_t ); -bool f64_le_quiet( float64_t, float64_t ); -bool f64_lt_quiet( float64_t, float64_t ); -bool f64_isSignalingNaN( float64_t ); - -/*---------------------------------------------------------------------------- -| Rounding precision for 80-bit extended double-precision floating-point. -| Valid values are 32, 64, and 80. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t extF80_roundingPrecision; - -/*---------------------------------------------------------------------------- -| 80-bit extended double-precision floating-point operations. -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast32_t extF80_to_ui32( extFloat80_t, uint_fast8_t, bool ); -uint_fast64_t extF80_to_ui64( extFloat80_t, uint_fast8_t, bool ); -int_fast32_t extF80_to_i32( extFloat80_t, uint_fast8_t, bool ); -int_fast64_t extF80_to_i64( extFloat80_t, uint_fast8_t, bool ); -uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t, bool ); -uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t, bool ); -int_fast32_t extF80_to_i32_r_minMag( extFloat80_t, bool ); -int_fast64_t extF80_to_i64_r_minMag( extFloat80_t, bool ); -float16_t extF80_to_f16( extFloat80_t ); -float32_t extF80_to_f32( extFloat80_t ); -float64_t extF80_to_f64( extFloat80_t ); -float128_t extF80_to_f128( extFloat80_t ); -extFloat80_t extF80_roundToInt( extFloat80_t, uint_fast8_t, bool ); -extFloat80_t extF80_add( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_sub( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_mul( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_div( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_rem( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_sqrt( extFloat80_t ); -bool extF80_eq( extFloat80_t, extFloat80_t ); -bool extF80_le( extFloat80_t, extFloat80_t ); -bool extF80_lt( extFloat80_t, extFloat80_t ); -bool extF80_eq_signaling( extFloat80_t, extFloat80_t ); -bool extF80_le_quiet( extFloat80_t, extFloat80_t ); -bool extF80_lt_quiet( extFloat80_t, extFloat80_t ); -bool extF80_isSignalingNaN( extFloat80_t ); -#endif -uint_fast32_t extF80M_to_ui32( const extFloat80_t *, uint_fast8_t, bool ); -uint_fast64_t extF80M_to_ui64( const extFloat80_t *, uint_fast8_t, bool ); -int_fast32_t extF80M_to_i32( const extFloat80_t *, uint_fast8_t, bool ); -int_fast64_t extF80M_to_i64( const extFloat80_t *, uint_fast8_t, bool ); -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *, bool ); -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *, bool ); -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *, bool ); -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *, bool ); -float16_t extF80M_to_f16( const extFloat80_t * ); -float32_t extF80M_to_f32( const extFloat80_t * ); -float64_t extF80M_to_f64( const extFloat80_t * ); -void extF80M_to_f128M( const extFloat80_t *, float128_t * ); -void - extF80M_roundToInt( - const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * ); -void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_div( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_rem( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_sqrt( const extFloat80_t *, extFloat80_t * ); -bool extF80M_eq( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_le( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_lt( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_eq_signaling( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_le_quiet( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_lt_quiet( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_isSignalingNaN( const extFloat80_t * ); - -/*---------------------------------------------------------------------------- -| 128-bit (quadruple-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast32_t f128_to_ui32( float128_t, uint_fast8_t, bool ); -uint_fast64_t f128_to_ui64( float128_t, uint_fast8_t, bool ); -int_fast32_t f128_to_i32( float128_t, uint_fast8_t, bool ); -int_fast64_t f128_to_i64( float128_t, uint_fast8_t, bool ); -uint_fast32_t f128_to_ui32_r_minMag( float128_t, bool ); -uint_fast64_t f128_to_ui64_r_minMag( float128_t, bool ); -int_fast32_t f128_to_i32_r_minMag( float128_t, bool ); -int_fast64_t f128_to_i64_r_minMag( float128_t, bool ); -float16_t f128_to_f16( float128_t ); -float32_t f128_to_f32( float128_t ); -float64_t f128_to_f64( float128_t ); -extFloat80_t f128_to_extF80( float128_t ); -float128_t f128_roundToInt( float128_t, uint_fast8_t, bool ); -float128_t f128_add( float128_t, float128_t ); -float128_t f128_sub( float128_t, float128_t ); -float128_t f128_mul( float128_t, float128_t ); -float128_t f128_mulAdd( float128_t, float128_t, float128_t ); -float128_t f128_div( float128_t, float128_t ); -float128_t f128_rem( float128_t, float128_t ); -float128_t f128_sqrt( float128_t ); -bool f128_eq( float128_t, float128_t ); -bool f128_le( float128_t, float128_t ); -bool f128_lt( float128_t, float128_t ); -bool f128_eq_signaling( float128_t, float128_t ); -bool f128_le_quiet( float128_t, float128_t ); -bool f128_lt_quiet( float128_t, float128_t ); -bool f128_isSignalingNaN( float128_t ); -#endif -uint_fast32_t f128M_to_ui32( const float128_t *, uint_fast8_t, bool ); -uint_fast64_t f128M_to_ui64( const float128_t *, uint_fast8_t, bool ); -int_fast32_t f128M_to_i32( const float128_t *, uint_fast8_t, bool ); -int_fast64_t f128M_to_i64( const float128_t *, uint_fast8_t, bool ); -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *, bool ); -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *, bool ); -int_fast32_t f128M_to_i32_r_minMag( const float128_t *, bool ); -int_fast64_t f128M_to_i64_r_minMag( const float128_t *, bool ); -float16_t f128M_to_f16( const float128_t * ); -float32_t f128M_to_f32( const float128_t * ); -float64_t f128M_to_f64( const float128_t * ); -void f128M_to_extF80M( const float128_t *, extFloat80_t * ); -void f128M_roundToInt( const float128_t *, uint_fast8_t, bool, float128_t * ); -void f128M_add( const float128_t *, const float128_t *, float128_t * ); -void f128M_sub( const float128_t *, const float128_t *, float128_t * ); -void f128M_mul( const float128_t *, const float128_t *, float128_t * ); -void - f128M_mulAdd( - const float128_t *, const float128_t *, const float128_t *, float128_t * - ); -void f128M_div( const float128_t *, const float128_t *, float128_t * ); -void f128M_rem( const float128_t *, const float128_t *, float128_t * ); -void f128M_sqrt( const float128_t *, float128_t * ); -bool f128M_eq( const float128_t *, const float128_t * ); -bool f128M_le( const float128_t *, const float128_t * ); -bool f128M_lt( const float128_t *, const float128_t * ); -bool f128M_eq_signaling( const float128_t *, const float128_t * ); -bool f128M_le_quiet( const float128_t *, const float128_t * ); -bool f128M_lt_quiet( const float128_t *, const float128_t * ); -bool f128M_isSignalingNaN( const float128_t * ); - -#endif - diff --git a/deps/SoftFloat-3e/source/include/softfloat_types.h b/deps/SoftFloat-3e/source/include/softfloat_types.h deleted file mode 100644 index 27507741af47..000000000000 --- a/deps/SoftFloat-3e/source/include/softfloat_types.h +++ /dev/null @@ -1,82 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef softfloat_types_h -#define softfloat_types_h 1 - -#include "platform.h" -#include - -/*---------------------------------------------------------------------------- -| Types used to pass 16-bit, 32-bit, 64-bit, and 128-bit floating-point -| arguments and results to/from functions. These types must be exactly -| 16 bits, 32 bits, 64 bits, and 128 bits in size, respectively. Where a -| platform has "native" support for IEEE-Standard floating-point formats, -| the types below may, if desired, be defined as aliases for the native types -| (typically 'float' and 'double', and possibly 'long double'). -*----------------------------------------------------------------------------*/ -typedef struct { uint16_t v; } float16_t; -typedef struct { uint32_t v; } float32_t; -typedef struct { uint64_t v; } float64_t; -typedef struct { uint64_t v[2]; } float128_t; - -/*---------------------------------------------------------------------------- -| The format of an 80-bit extended floating-point number in memory. This -| structure must contain a 16-bit field named 'signExp' and a 64-bit field -| named 'signif'. -*----------------------------------------------------------------------------*/ -#ifdef LITTLEENDIAN -struct extFloat80M { uint64_t signif; uint16_t signExp; }; -#else -struct extFloat80M { uint16_t signExp; uint64_t signif; }; -#endif - -/*---------------------------------------------------------------------------- -| The type used to pass 80-bit extended floating-point arguments and -| results to/from functions. This type must have size identical to -| 'struct extFloat80M'. Type 'extFloat80_t' can be defined as an alias for -| 'struct extFloat80M'. Alternatively, if a platform has "native" support -| for IEEE-Standard 80-bit extended floating-point, it may be possible, -| if desired, to define 'extFloat80_t' as an alias for the native type -| (presumably either 'long double' or a nonstandard compiler-intrinsic type). -| In that case, the 'signif' and 'signExp' fields of 'struct extFloat80M' -| must align exactly with the locations in memory of the sign, exponent, and -| significand of the native type. -*----------------------------------------------------------------------------*/ -typedef struct extFloat80M extFloat80_t; - -#endif - diff --git a/deps/SoftFloat-3e/source/s_add128.c b/deps/SoftFloat-3e/source/s_add128.c deleted file mode 100644 index 5a9d5082a0b7..000000000000 --- a/deps/SoftFloat-3e/source/s_add128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_add128 - -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - - z.v0 = a0 + b0; - z.v64 = a64 + b64 + (z.v0 < a0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_add256M.c b/deps/SoftFloat-3e/source/s_add256M.c deleted file mode 100644 index 4fb46a1742cb..000000000000 --- a/deps/SoftFloat-3e/source/s_add256M.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_add256M - -void - softfloat_add256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) -{ - unsigned int index; - uint_fast8_t carry; - uint64_t wordA, wordZ; - - index = indexWordLo( 4 ); - carry = 0; - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( index == indexWordHi( 4 ) ) break; - if ( wordZ != wordA ) carry = (wordZ < wordA); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addCarryM.c b/deps/SoftFloat-3e/source/s_addCarryM.c deleted file mode 100644 index f0ccf6724764..000000000000 --- a/deps/SoftFloat-3e/source/s_addCarryM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addCarryM - -uint_fast8_t - softfloat_addCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( wordZ != wordA ) carry = (wordZ < wordA); - if ( index == lastIndex ) break; - index += wordIncr; - } - return carry; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addComplCarryM.c b/deps/SoftFloat-3e/source/s_addComplCarryM.c deleted file mode 100644 index e1584c669a18..000000000000 --- a/deps/SoftFloat-3e/source/s_addComplCarryM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addComplCarryM - -uint_fast8_t - softfloat_addComplCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + ~bPtr[index] + carry; - zPtr[index] = wordZ; - if ( wordZ != wordA ) carry = (wordZ < wordA); - if ( index == lastIndex ) break; - index += wordIncr; - } - return carry; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addExtF80M.c b/deps/SoftFloat-3e/source/s_addExtF80M.c deleted file mode 100644 index febfb65773dd..000000000000 --- a/deps/SoftFloat-3e/source/s_addExtF80M.c +++ /dev/null @@ -1,186 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_addExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr, - bool negateB - ) -{ - uint32_t uiA64; - int32_t expA; - uint32_t uiB64; - int32_t expB; - uint32_t uiZ64; - bool signZ, signB; - const struct extFloat80M *tempSPtr; - uint64_t sigZ, sigB; - void - (*roundPackRoutinePtr)( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); - int32_t expDiff; - uint32_t extSigX[3], sigZExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - uiZ64 = uiA64; - if ( expB == 0x7FFF ) { - uiZ64 = uiB64 ^ packToExtF80UI64( negateB, 0 ); - if ( (expA == 0x7FFF) && (uiZ64 != uiA64) ) { - softfloat_invalidExtF80M( zSPtr ); - return; - } - } - zSPtr->signExp = uiZ64; - zSPtr->signif = UINT64_C( 0x8000000000000000 ); - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signZ = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ) ^ negateB; - negateB = (signZ != signB); - if ( expA < expB ) { - signZ = signB; - expA = expB; - expB = expExtF80UI64( uiA64 ); - tempSPtr = aSPtr; - aSPtr = bSPtr; - bSPtr = tempSPtr; - } - if ( ! expB ) { - expB = 1; - if ( ! expA ) expA = 1; - } - sigZ = aSPtr->signif; - sigB = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPackRoutinePtr = softfloat_roundPackMToExtF80M; - expDiff = expA - expB; - if ( expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigX[indexWord( 3, 2 )] = sigB>>32; - extSigX[indexWord( 3, 1 )] = sigB; - extSigX[indexWord( 3, 0 )] = 0; - softfloat_shiftRightJam96M( extSigX, expDiff, extSigX ); - sigB = - (uint64_t) extSigX[indexWord( 3, 2 )]<<32 - | extSigX[indexWord( 3, 1 )]; - if ( negateB ) { - sigZ -= sigB; - sigZExtra = extSigX[indexWordLo( 3 )]; - if ( sigZExtra ) { - --sigZ; - sigZExtra = -sigZExtra; - } - if ( ! (sigZ & UINT64_C( 0x8000000000000000 )) ) { - if ( sigZ & UINT64_C( 0x4000000000000000 ) ) { - --expA; - sigZ = sigZ<<1 | sigZExtra>>31; - sigZExtra <<= 1; - } else { - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } - } - } else { - sigZ += sigB; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto sigZ; - sigZExtra = (uint32_t) sigZ<<31 | (extSigX[indexWordLo( 3 )] != 0); - goto completeNormAfterAdd; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigZExtra = 0; - if ( negateB ) { - if ( sigZ < sigB ) { - signZ = ! signZ; - sigZ = sigB - sigZ; - } else { - sigZ -= sigB; - if ( ! sigZ ) { - signZ = (softfloat_roundingMode == softfloat_round_min); - zSPtr->signExp = packToExtF80UI64( signZ, 0 ); - zSPtr->signif = 0; - return; - } - } - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } else { - sigZ += sigB; - if ( sigZ < sigB ) { - sigZExtra = (uint32_t) sigZ<<31; - completeNormAfterAdd: - ++expA; - sigZ = UINT64_C( 0x8000000000000000 ) | sigZ>>1; - } else { - if ( ! (sigZ & UINT64_C( 0x8000000000000000 )) ) { - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } - } - } - } - extSigX[indexWord( 3, 0 )] = sigZExtra; - sigZ: - extSigX[indexWord( 3, 2 )] = sigZ>>32; - extSigX[indexWord( 3, 1 )] = sigZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPack: - (*roundPackRoutinePtr)( - signZ, expA, extSigX, extF80_roundingPrecision, zSPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_addF128M.c b/deps/SoftFloat-3e/source/s_addF128M.c deleted file mode 100644 index 8ed9d271fabb..000000000000 --- a/deps/SoftFloat-3e/source/s_addF128M.c +++ /dev/null @@ -1,211 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_addF128M( - const uint32_t *aWPtr, - const uint32_t *bWPtr, - uint32_t *zWPtr, - bool negateB - ) -{ - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - uint32_t uiZ96; - bool signZ, signB; - const uint32_t *tempPtr; - uint32_t sig96A, sig96B; - int32_t expDiff; - uint_fast8_t - (*addCarryMRoutinePtr)( - uint_fast8_t, - const uint32_t *, - const uint32_t *, - uint_fast8_t, - uint32_t * - ); - uint32_t extSigZ[5], wordSigZ; - uint_fast8_t carry; - void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - uiZ96 = uiA96; - if ( expB == 0x7FFF ) { - uiZ96 = uiB96 ^ packToF128UI96( negateB, 0, 0 ); - if ( (expA == 0x7FFF) && (uiZ96 != uiA96) ) { - softfloat_invalidF128M( zWPtr ); - return; - } - } - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signZ = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ) ^ negateB; - negateB = (signZ != signB); - if ( (uint32_t) (uiA96<<1) < (uint32_t) (uiB96<<1) ) { - signZ = signB; - expA = expB; - expB = expF128UI96( uiA96 ); - tempPtr = aWPtr; - aWPtr = bWPtr; - bWPtr = tempPtr; - uiA96 = uiB96; - uiB96 = bWPtr[indexWordHi( 4 )]; - } - sig96A = fracF128UI96( uiA96 ); - sig96B = fracF128UI96( uiB96 ); - if ( expA ) { - --expA; - sig96A |= 0x00010000; - if ( expB ) { - --expB; - sig96B |= 0x00010000; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - addCarryMRoutinePtr = - negateB ? softfloat_addComplCarryM : softfloat_addCarryM; - expDiff = expA - expB; - if ( expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigZ[indexWordHi( 5 )] = sig96B; - extSigZ[indexWord( 5, 3 )] = bWPtr[indexWord( 4, 2 )]; - extSigZ[indexWord( 5, 2 )] = bWPtr[indexWord( 4, 1 )]; - extSigZ[indexWord( 5, 1 )] = bWPtr[indexWord( 4, 0 )]; - extSigZ[indexWord( 5, 0 )] = 0; - softfloat_shiftRightJam160M( extSigZ, expDiff, extSigZ ); - sig96B = extSigZ[indexWordHi( 5 )]; - carry = 0; - if ( negateB ) { - sig96B = ~sig96B; - wordSigZ = extSigZ[indexWordLo( 5 )]; - extSigZ[indexWordLo( 5 )] = -wordSigZ; - carry = ! wordSigZ; - } - carry = - (*addCarryMRoutinePtr)( - 3, - &aWPtr[indexMultiwordLo( 4, 3 )], - &extSigZ[indexMultiword( 5, 3, 1 )], - carry, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - wordSigZ = sig96A + sig96B + carry; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigZ[indexWordLo( 5 )] = 0; - carry = - (*addCarryMRoutinePtr)( - 3, - &aWPtr[indexMultiwordLo( 4, 3 )], - &bWPtr[indexMultiwordLo( 4, 3 )], - negateB, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - if ( negateB ) { - wordSigZ = sig96A + ~sig96B + carry; - if ( wordSigZ & 0x80000000 ) { - signZ = ! signZ; - carry = - softfloat_addComplCarry96M( - &bWPtr[indexMultiwordLo( 4, 3 )], - &aWPtr[indexMultiwordLo( 4, 3 )], - 1, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - wordSigZ = sig96B + ~sig96A + carry; - } else { - if ( - ! wordSigZ && ! extSigZ[indexWord( 5, 3 )] - && ! ( extSigZ[indexWord( 5, 2 )] - | extSigZ[indexWord( 5, 1 )] - | extSigZ[indexWord( 5, 0 )] - ) - ) { - signZ = (softfloat_roundingMode == softfloat_round_min); - zWPtr[indexWordHi( 4 )] = packToF128UI96( signZ, 0, 0 ); - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - } - } else { - wordSigZ = sig96A + sig96B + carry; - } - } - extSigZ[indexWordHi( 5 )] = wordSigZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPackRoutinePtr = softfloat_normRoundPackMToF128M; - if ( 0x00010000 <= wordSigZ ) { - if ( 0x00020000 <= wordSigZ ) { - ++expA; - softfloat_shortShiftRightJam160M( extSigZ, 1, extSigZ ); - } - roundPackRoutinePtr = softfloat_roundPackMToF128M; - } - (*roundPackRoutinePtr)( signZ, expA, extSigZ, zWPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_addM.c b/deps/SoftFloat-3e/source/s_addM.c deleted file mode 100644 index c935baaf7c9e..000000000000 --- a/deps/SoftFloat-3e/source/s_addM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addM - -void - softfloat_addM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint_fast8_t carry; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - carry = 0; - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( index == lastIndex ) break; - if ( wordZ != wordA ) carry = (wordZ < wordA); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addMagsExtF80.c b/deps/SoftFloat-3e/source/s_addMagsExtF80.c deleted file mode 100644 index b1bb5dbe64a7..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsExtF80.c +++ /dev/null @@ -1,156 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - softfloat_addMagsExtF80( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - uint_fast64_t sigA; - int_fast32_t expB; - uint_fast64_t sigB; - int_fast32_t expDiff; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0, sigZ, sigZExtra; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint64_extra sig64Extra; - struct uint128 uiZ; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - if ( expA == 0x7FFF ) { - if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - goto propagateNaN; - } - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - sigZ = sigA + sigB; - sigZExtra = 0; - if ( ! expA ) { - normExpSig = softfloat_normSubnormalExtF80Sig( sigZ ); - expZ = normExpSig.exp + 1; - sigZ = normExpSig.sig; - goto roundAndPack; - } - expZ = expA; - goto shiftRight1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = uiB0; - goto uiZ; - } - expZ = expB; - if ( ! expA ) { - ++expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig64Extra = softfloat_shiftRightJam64Extra( sigA, 0, -expDiff ); - sigA = sig64Extra.v; - sigZExtra = sig64Extra.extra; - } else { - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - expZ = expA; - if ( ! expB ) { - --expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig64Extra = softfloat_shiftRightJam64Extra( sigB, 0, expDiff ); - sigB = sig64Extra.v; - sigZExtra = sig64Extra.extra; - } - newlyAligned: - sigZ = sigA + sigB; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto roundAndPack; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftRight1: - sig64Extra = softfloat_shortShiftRightJam64Extra( sigZ, sigZExtra, 1 ); - sigZ = sig64Extra.v | UINT64_C( 0x8000000000000000 ); - sigZExtra = sig64Extra.extra; - ++expZ; - roundAndPack: - return - softfloat_roundPackToExtF80( - signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF128.c b/deps/SoftFloat-3e/source/s_addMagsF128.c deleted file mode 100644 index 8e5ce5b34e16..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF128.c +++ /dev/null @@ -1,154 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float128_t - softfloat_addMagsF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - struct uint128 sigA; - int_fast32_t expB; - struct uint128 sigB; - int_fast32_t expDiff; - struct uint128 uiZ, sigZ; - int_fast32_t expZ; - uint_fast64_t sigZExtra; - struct uint128_extra sig128Extra; - union ui128_f128 uZ; - - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - expDiff = expA - expB; - if ( ! expDiff ) { - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - sigZ = softfloat_add128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); - if ( ! expA ) { - uiZ.v64 = packToF128UI64( signZ, 0, sigZ.v64 ); - uiZ.v0 = sigZ.v0; - goto uiZ; - } - expZ = expA; - sigZ.v64 |= UINT64_C( 0x0002000000000000 ); - sigZExtra = 0; - goto shiftRight1; - } - if ( expDiff < 0 ) { - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - expZ = expB; - if ( expA ) { - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - } else { - ++expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig128Extra = - softfloat_shiftRightJam128Extra( sigA.v64, sigA.v0, 0, -expDiff ); - sigA = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } else { - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - expZ = expA; - if ( expB ) { - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - } else { - --expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig128Extra = - softfloat_shiftRightJam128Extra( sigB.v64, sigB.v0, 0, expDiff ); - sigB = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } - newlyAligned: - sigZ = - softfloat_add128( - sigA.v64 | UINT64_C( 0x0001000000000000 ), - sigA.v0, - sigB.v64, - sigB.v0 - ); - --expZ; - if ( sigZ.v64 < UINT64_C( 0x0002000000000000 ) ) goto roundAndPack; - ++expZ; - shiftRight1: - sig128Extra = - softfloat_shortShiftRightJam128Extra( - sigZ.v64, sigZ.v0, sigZExtra, 1 ); - sigZ = sig128Extra.v; - sigZExtra = sig128Extra.extra; - roundAndPack: - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF16.c b/deps/SoftFloat-3e/source/s_addMagsF16.c deleted file mode 100644 index b7fba09283e8..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF16.c +++ /dev/null @@ -1,183 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t softfloat_addMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - int_fast8_t expA; - uint_fast16_t sigA; - int_fast8_t expB; - uint_fast16_t sigB; - int_fast8_t expDiff; - uint_fast16_t uiZ; - bool signZ; - int_fast8_t expZ; - uint_fast16_t sigZ; - uint_fast16_t sigX, sigY; - int_fast8_t shiftDist; - uint_fast32_t sig32Z; - int_fast8_t roundingMode; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0x1F ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - signZ = signF16UI( uiA ); - expZ = expA; - sigZ = 0x0800 + sigA + sigB; - if ( ! (sigZ & 1) && (expZ < 0x1E) ) { - sigZ >>= 1; - goto pack; - } - sigZ <<= 3; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signF16UI( uiA ); - if ( expDiff < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF16UI( signZ, 0x1F, 0 ); - goto uiZ; - } - if ( expDiff <= -13 ) { - uiZ = packToF16UI( signZ, expB, sigB ); - if ( expA | sigA ) goto addEpsilon; - goto uiZ; - } - expZ = expB; - sigX = sigB | 0x0400; - sigY = sigA + (expA ? 0x0400 : sigA); - shiftDist = 19 + expDiff; - } else { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - uiZ = uiA; - if ( expA == 0x1F ) { - if ( sigA ) goto propagateNaN; - goto uiZ; - } - if ( 13 <= expDiff ) { - if ( expB | sigB ) goto addEpsilon; - goto uiZ; - } - expZ = expA; - sigX = sigA | 0x0400; - sigY = sigB + (expB ? 0x0400 : sigB); - shiftDist = 19 - expDiff; - } - sig32Z = - ((uint_fast32_t) sigX<<19) + ((uint_fast32_t) sigY<>16; - if ( sig32Z & 0xFFFF ) { - sigZ |= 1; - } else { - if ( ! (sigZ & 0xF) && (expZ < 0x1E) ) { - sigZ >>= 4; - goto pack; - } - } - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - addEpsilon: - roundingMode = softfloat_roundingMode; - if ( roundingMode != softfloat_round_near_even ) { - if ( - roundingMode - == (signF16UI( uiZ ) ? softfloat_round_min - : softfloat_round_max) - ) { - ++uiZ; - if ( (uint16_t) (uiZ<<1) == 0xF800 ) { - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - } - } -#ifdef SOFTFLOAT_ROUND_ODD - else if ( roundingMode == softfloat_round_odd ) { - uiZ |= 1; - } -#endif - } - softfloat_exceptionFlags |= softfloat_flag_inexact; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - pack: - uiZ = packToF16UI( signZ, expZ, sigZ ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF32.c b/deps/SoftFloat-3e/source/s_addMagsF32.c deleted file mode 100644 index b74489decefe..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF32.c +++ /dev/null @@ -1,126 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float32_t softfloat_addMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - int_fast16_t expA; - uint_fast32_t sigA; - int_fast16_t expB; - uint_fast32_t sigB; - int_fast16_t expDiff; - uint_fast32_t uiZ; - bool signZ; - int_fast16_t expZ; - uint_fast32_t sigZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0xFF ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - signZ = signF32UI( uiA ); - expZ = expA; - sigZ = 0x01000000 + sigA + sigB; - if ( ! (sigZ & 1) && (expZ < 0xFE) ) { - uiZ = packToF32UI( signZ, expZ, sigZ>>1 ); - goto uiZ; - } - sigZ <<= 6; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signF32UI( uiA ); - sigA <<= 6; - sigB <<= 6; - if ( expDiff < 0 ) { - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF32UI( signZ, 0xFF, 0 ); - goto uiZ; - } - expZ = expB; - sigA += expA ? 0x20000000 : sigA; - sigA = softfloat_shiftRightJam32( sigA, -expDiff ); - } else { - if ( expA == 0xFF ) { - if ( sigA ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - sigB += expB ? 0x20000000 : sigB; - sigB = softfloat_shiftRightJam32( sigB, expDiff ); - } - sigZ = 0x20000000 + sigA + sigB; - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - } - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF64.c b/deps/SoftFloat-3e/source/s_addMagsF64.c deleted file mode 100644 index e8a489874562..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF64.c +++ /dev/null @@ -1,128 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float64_t - softfloat_addMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) -{ - int_fast16_t expA; - uint_fast64_t sigA; - int_fast16_t expB; - uint_fast64_t sigB; - int_fast16_t expDiff; - uint_fast64_t uiZ; - int_fast16_t expZ; - uint_fast64_t sigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0x7FF ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - sigZ = UINT64_C( 0x0020000000000000 ) + sigA + sigB; - sigZ <<= 9; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigA <<= 9; - sigB <<= 9; - if ( expDiff < 0 ) { - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - goto uiZ; - } - expZ = expB; - if ( expA ) { - sigA += UINT64_C( 0x2000000000000000 ); - } else { - sigA <<= 1; - } - sigA = softfloat_shiftRightJam64( sigA, -expDiff ); - } else { - if ( expA == 0x7FF ) { - if ( sigA ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - if ( expB ) { - sigB += UINT64_C( 0x2000000000000000 ); - } else { - sigB <<= 1; - } - sigB = softfloat_shiftRightJam64( sigB, expDiff ); - } - sigZ = UINT64_C( 0x2000000000000000 ) + sigA + sigB; - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_approxRecip32_1.c b/deps/SoftFloat-3e/source/s_approxRecip32_1.c deleted file mode 100644 index 4a326a438fe4..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecip32_1.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_approxRecip32_1 - -extern const uint16_t softfloat_approxRecip_1k0s[16]; -extern const uint16_t softfloat_approxRecip_1k1s[16]; - -uint32_t softfloat_approxRecip32_1( uint32_t a ) -{ - int index; - uint16_t eps, r0; - uint32_t sigma0; - uint_fast32_t r; - uint32_t sqrSigma0; - - index = a>>27 & 0xF; - eps = (uint16_t) (a>>11); - r0 = softfloat_approxRecip_1k0s[index] - - ((softfloat_approxRecip_1k1s[index] * (uint_fast32_t) eps)>>20); - sigma0 = ~(uint_fast32_t) ((r0 * (uint_fast64_t) a)>>7); - r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>24); - sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; - r += ((uint32_t) r * (uint_fast64_t) sqrSigma0)>>48; - return r; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c b/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c deleted file mode 100644 index b3fdeba68b75..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_approxRecipSqrt32_1 - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; - -uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ) -{ - int index; - uint16_t eps, r0; - uint_fast32_t ESqrR0; - uint32_t sigma0; - uint_fast32_t r; - uint32_t sqrSigma0; - - index = (a>>27 & 0xE) + oddExpA; - eps = (uint16_t) (a>>12); - r0 = softfloat_approxRecipSqrt_1k0s[index] - - ((softfloat_approxRecipSqrt_1k1s[index] * (uint_fast32_t) eps) - >>20); - ESqrR0 = (uint_fast32_t) r0 * r0; - if ( ! oddExpA ) ESqrR0 <<= 1; - sigma0 = ~(uint_fast32_t) (((uint32_t) ESqrR0 * (uint_fast64_t) a)>>23); - r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>25); - sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; - r += ((uint32_t) ((r>>1) + (r>>3) - ((uint_fast32_t) r0<<14)) - * (uint_fast64_t) sqrSigma0) - >>48; - if ( ! (r & 0x80000000) ) r = 0x80000000; - return r; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c b/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c deleted file mode 100644 index 38a27985c03e..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint16_t softfloat_approxRecipSqrt_1k0s[16] = { - 0xB4C9, 0xFFAB, 0xAA7D, 0xF11C, 0xA1C5, 0xE4C7, 0x9A43, 0xDA29, - 0x93B5, 0xD0E5, 0x8DED, 0xC8B7, 0x88C6, 0xC16D, 0x8424, 0xBAE1 -}; -const uint16_t softfloat_approxRecipSqrt_1k1s[16] = { - 0xA5A5, 0xEA42, 0x8C21, 0xC62D, 0x788F, 0xAA7F, 0x6928, 0x94B6, - 0x5CC7, 0x8335, 0x52A6, 0x74E2, 0x4A3E, 0x68FE, 0x432B, 0x5EFD -}; - diff --git a/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c b/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c deleted file mode 100644 index f1fca74e73b7..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint16_t softfloat_approxRecip_1k0s[16] = { - 0xFFC4, 0xF0BE, 0xE363, 0xD76F, 0xCCAD, 0xC2F0, 0xBA16, 0xB201, - 0xAA97, 0xA3C6, 0x9D7A, 0x97A6, 0x923C, 0x8D32, 0x887E, 0x8417 -}; -const uint16_t softfloat_approxRecip_1k1s[16] = { - 0xF0F1, 0xD62C, 0xBFA1, 0xAC77, 0x9C0A, 0x8DDB, 0x8185, 0x76BA, - 0x6D3B, 0x64D4, 0x5D5C, 0x56B1, 0x50B6, 0x4B55, 0x4679, 0x4211 -}; - diff --git a/deps/SoftFloat-3e/source/s_compare128M.c b/deps/SoftFloat-3e/source/s_compare128M.c deleted file mode 100644 index dc97ce9e5015..000000000000 --- a/deps/SoftFloat-3e/source/s_compare128M.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_compare128M - -int_fast8_t softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordB; - - index = indexWordHi( 4 ); - lastIndex = indexWordLo( 4 ); - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; - if ( index == lastIndex ) break; - index -= wordIncr; - } - return 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_compare96M.c b/deps/SoftFloat-3e/source/s_compare96M.c deleted file mode 100644 index 2681c46274ac..000000000000 --- a/deps/SoftFloat-3e/source/s_compare96M.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_compare96M - -int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordB; - - index = indexWordHi( 3 ); - lastIndex = indexWordLo( 3 ); - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; - if ( index == lastIndex ) break; - index -= wordIncr; - } - return 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c b/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c deleted file mode 100644 index 2673153048c1..000000000000 --- a/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat_types.h" - -int - softfloat_compareNonnormExtF80M( - const struct extFloat80M *aSPtr, const struct extFloat80M *bSPtr ) -{ - uint_fast16_t uiA64, uiB64; - uint64_t sigA; - bool signB; - uint64_t sigB; - int32_t expA, expB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiB64 = bSPtr->signExp; - sigA = aSPtr->signif; - signB = signExtF80UI64( uiB64 ); - sigB = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (uiA64 ^ uiB64) & 0x8000 ) { - if ( ! (sigA | sigB) ) return 0; - goto resultFromSignB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - expB = expExtF80UI64( uiB64 ); - if ( expA == 0x7FFF ) { - if (expB == 0x7FFF) return 0; - signB = ! signB; - goto resultFromSignB; - } - if ( expB == 0x7FFF ) { - goto resultFromSignB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( sigA ) { - expA += softfloat_normExtF80SigM( &sigA ); - } else { - expA = -128; - } - } - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( sigB ) { - expB += softfloat_normExtF80SigM( &sigB ); - } else { - expB = -128; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signB ) { - if ( expA < expB ) return 1; - if ( (expB < expA) || (sigB < sigA) ) return -1; - } else { - if ( expB < expA ) return 1; - if ( (expA < expB) || (sigA < sigB) ) return -1; - } - return (sigA != sigB); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - resultFromSignB: - return signB ? 1 : -1; - -} - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros16.c b/deps/SoftFloat-3e/source/s_countLeadingZeros16.c deleted file mode 100644 index 7a68da52f35e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros16.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros16 - -#define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) -{ - uint_fast8_t count; - - count = 8; - if ( 0x100 <= a ) { - count = 0; - a >>= 8; - } - count += softfloat_countLeadingZeros8[a]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros32.c b/deps/SoftFloat-3e/source/s_countLeadingZeros32.c deleted file mode 100644 index 53ab22824f7e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros32.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros32 - -#define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) -{ - uint_fast8_t count; - - count = 0; - if ( a < 0x10000 ) { - count = 16; - a <<= 16; - } - if ( a < 0x1000000 ) { - count += 8; - a <<= 8; - } - count += softfloat_countLeadingZeros8[a>>24]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros64.c b/deps/SoftFloat-3e/source/s_countLeadingZeros64.c deleted file mode 100644 index 13a222463643..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros64.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros64 - -#define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ) -{ - uint_fast8_t count; - uint32_t a32; - - count = 0; - a32 = a>>32; - if ( ! a32 ) { - count = 32; - a32 = a; - } - /*------------------------------------------------------------------------ - | From here, result is current count + count leading zeros of `a32'. - *------------------------------------------------------------------------*/ - if ( a32 < 0x10000 ) { - count += 16; - a32 <<= 16; - } - if ( a32 < 0x1000000 ) { - count += 8; - a32 <<= 8; - } - count += softfloat_countLeadingZeros8[a32>>24]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros8.c b/deps/SoftFloat-3e/source/s_countLeadingZeros8.c deleted file mode 100644 index a56f5a40c52e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros8.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint_least8_t softfloat_countLeadingZeros8[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - diff --git a/deps/SoftFloat-3e/source/s_eq128.c b/deps/SoftFloat-3e/source/s_eq128.c deleted file mode 100644 index 275b8ae29942..000000000000 --- a/deps/SoftFloat-3e/source/s_eq128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_eq128 - -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 == b64) && (a0 == b0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_invalidExtF80M.c b/deps/SoftFloat-3e/source/s_invalidExtF80M.c deleted file mode 100644 index 237d217212ef..000000000000 --- a/deps/SoftFloat-3e/source/s_invalidExtF80M.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -void softfloat_invalidExtF80M( struct extFloat80M *zSPtr ) -{ - - softfloat_raiseFlags( softfloat_flag_invalid ); - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/s_invalidF128M.c b/deps/SoftFloat-3e/source/s_invalidF128M.c deleted file mode 100644 index a20840e5f556..000000000000 --- a/deps/SoftFloat-3e/source/s_invalidF128M.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -void softfloat_invalidF128M( uint32_t *zWPtr ) -{ - - softfloat_raiseFlags( softfloat_flag_invalid ); - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/s_isNaNF128M.c b/deps/SoftFloat-3e/source/s_isNaNF128M.c deleted file mode 100644 index 6008cf3ebc19..000000000000 --- a/deps/SoftFloat-3e/source/s_isNaNF128M.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool softfloat_isNaNF128M( const uint32_t *aWPtr ) -{ - uint32_t uiA96; - - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (~uiA96 & 0x7FFF0000) != 0 ) return false; - return - ((uiA96 & 0x0000FFFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/s_le128.c b/deps/SoftFloat-3e/source/s_le128.c deleted file mode 100644 index 1fce7af98ea2..000000000000 --- a/deps/SoftFloat-3e/source/s_le128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_le128 - -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_lt128.c b/deps/SoftFloat-3e/source/s_lt128.c deleted file mode 100644 index d7ce3b997154..000000000000 --- a/deps/SoftFloat-3e/source/s_lt128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_lt128 - -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 < b64) || ((a64 == b64) && (a0 < b0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128By32.c b/deps/SoftFloat-3e/source/s_mul128By32.c deleted file mode 100644 index 7c0fdc867949..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128By32.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul128By32 - -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - struct uint128 z; - uint_fast64_t mid; - uint_fast32_t carry; - - z.v0 = a0 * b; - mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; - carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); - z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128MTo256M.c b/deps/SoftFloat-3e/source/s_mul128MTo256M.c deleted file mode 100644 index ea8865ea3529..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128MTo256M.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul128MTo256M - -void - softfloat_mul128MTo256M( - const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) -{ - uint32_t *lastZPtr, wordB; - uint64_t dwordProd; - uint32_t wordZ; - uint_fast8_t carry; - - bPtr += indexWordLo( 4 ); - lastZPtr = zPtr + indexMultiwordHi( 8, 5 ); - zPtr += indexMultiwordLo( 8, 5 ); - wordB = *bPtr; - dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; - zPtr[indexWord( 5, 0 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 1 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 2 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 3 )] = dwordProd; - zPtr[indexWord( 5, 4 )] = dwordProd>>32; - do { - bPtr += wordIncr; - zPtr += wordIncr; - wordB = *bPtr; - dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; - wordZ = zPtr[indexWord( 5, 0 )] + (uint32_t) dwordProd; - zPtr[indexWord( 5, 0 )] = wordZ; - carry = (wordZ < (uint32_t) dwordProd); - dwordProd = - (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 1 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 1 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - dwordProd = - (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 2 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 2 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - dwordProd = - (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 3 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 3 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - zPtr[indexWord( 5, 4 )] = (dwordProd>>32) + carry; - } while ( zPtr != lastZPtr ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128To256M.c b/deps/SoftFloat-3e/source/s_mul128To256M.c deleted file mode 100644 index 7c9d9b584140..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128To256M.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_mul128To256M - -#define softfloat_mul128To256M softfloat_mul128To256M -#include "primitives.h" - -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ) -{ - struct uint128 p0, p64, p128; - uint_fast64_t z64, z128, z192; - - p0 = softfloat_mul64To128( a0, b0 ); - zPtr[indexWord( 4, 0 )] = p0.v0; - p64 = softfloat_mul64To128( a64, b0 ); - z64 = p64.v0 + p0.v64; - z128 = p64.v64 + (z64 < p64.v0); - p128 = softfloat_mul64To128( a64, b64 ); - z128 += p128.v0; - z192 = p128.v64 + (z128 < p128.v0); - p64 = softfloat_mul64To128( a0, b64 ); - z64 += p64.v0; - zPtr[indexWord( 4, 1 )] = z64; - p64.v64 += (z64 < p64.v0); - z128 += p64.v64; - zPtr[indexWord( 4, 2 )] = z128; - zPtr[indexWord( 4, 3 )] = z192 + (z128 < p64.v64); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c b/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c deleted file mode 100644 index 57e528888bfd..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64ByShifted32To128 - -struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - uint_fast64_t mid; - struct uint128 z; - - mid = (uint_fast64_t) (uint32_t) a * b; - z.v0 = mid<<32; - z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64To128.c b/deps/SoftFloat-3e/source/s_mul64To128.c deleted file mode 100644 index 5d360aa4b81e..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64To128.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64To128 - -struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ) -{ - uint32_t a32, a0, b32, b0; - struct uint128 z; - uint64_t mid1, mid; - - a32 = a>>32; - a0 = a; - b32 = b>>32; - b0 = b; - z.v0 = (uint_fast64_t) a0 * b0; - mid1 = (uint_fast64_t) a32 * b0; - mid = mid1 + (uint_fast64_t) a0 * b32; - z.v64 = (uint_fast64_t) a32 * b32; - z.v64 += (uint_fast64_t) (mid < mid1)<<32 | mid>>32; - mid <<= 32; - z.v0 += mid; - z.v64 += (z.v0 < mid); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64To128M.c b/deps/SoftFloat-3e/source/s_mul64To128M.c deleted file mode 100644 index ed10be3243db..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64To128M.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64To128M - -void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ) -{ - uint32_t a32, a0, b32, b0; - uint64_t z0, mid1, z64, mid; - - a32 = a>>32; - a0 = a; - b32 = b>>32; - b0 = b; - z0 = (uint64_t) a0 * b0; - mid1 = (uint64_t) a32 * b0; - mid = mid1 + (uint64_t) a0 * b32; - z64 = (uint64_t) a32 * b32; - z64 += (uint64_t) (mid < mid1)<<32 | mid>>32; - mid <<= 32; - z0 += mid; - zPtr[indexWord( 4, 1 )] = z0>>32; - zPtr[indexWord( 4, 0 )] = z0; - z64 += (z0 < mid); - zPtr[indexWord( 4, 3 )] = z64>>32; - zPtr[indexWord( 4, 2 )] = z64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mulAddF128.c b/deps/SoftFloat-3e/source/s_mulAddF128.c deleted file mode 100644 index f6b2b45df0ca..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF128.c +++ /dev/null @@ -1,350 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - softfloat_mulAddF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - uint_fast64_t uiC64, - uint_fast64_t uiC0, - uint_fast8_t op - ) -{ - bool signA; - int_fast32_t expA; - struct uint128 sigA; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signC; - int_fast32_t expC; - struct uint128 sigC; - bool signZ; - uint_fast64_t magBits; - struct uint128 uiZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint64_t sig256Z[4]; - struct uint128 sigZ; - int_fast32_t shiftDist, expDiff; - struct uint128 x128; - uint64_t sig256C[4]; - static uint64_t zero256[4] = INIT_UINTM4( 0, 0, 0, 0 ); - uint_fast64_t sigZExtra, sig256Z0; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signC = signF128UI64( uiC64 ) ^ (op == softfloat_mulAdd_subC); - expC = expF128UI64( uiC64 ); - sigC.v64 = fracF128UI64( uiC64 ); - sigC.v0 = uiC0; - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN_ABC; - } - magBits = expB | sigB.v64 | sigB.v0; - goto infProdArg; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN_ABC; - magBits = expA | sigA.v64 | sigA.v0; - goto infProdArg; - } - if ( expC == 0x7FFF ) { - if ( sigC.v64 | sigC.v0 ) { - uiZ.v64 = 0; - uiZ.v0 = 0; - goto propagateNaN_ZC; - } - uiZ.v64 = uiC64; - uiZ.v0 = uiC0; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zeroProd; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto zeroProd; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 8 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 15 ); - softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - shiftDist = 0; - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = -1; - } - if ( ! expC ) { - if ( ! (sigC.v64 | sigC.v0) ) { - shiftDist += 8; - goto sigZ; - } - normExpSig = softfloat_normSubnormalF128Sig( sigC.v64, sigC.v0 ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC.v64 |= UINT64_C( 0x0001000000000000 ); - sigC = softfloat_shortShiftLeft128( sigC.v64, sigC.v0, 8 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - shiftDist -= expDiff; - if ( shiftDist ) { - sigZ = - softfloat_shiftRightJam128( sigZ.v64, sigZ.v0, shiftDist ); - } - } else { - if ( ! shiftDist ) { - x128 = - softfloat_shortShiftRight128( - sig256Z[indexWord( 4, 1 )], sig256Z[indexWord( 4, 0 )], - 1 - ); - sig256Z[indexWord( 4, 1 )] = (sigZ.v0<<63) | x128.v64; - sig256Z[indexWord( 4, 0 )] = x128.v0; - sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, 1 ); - sig256Z[indexWord( 4, 3 )] = sigZ.v64; - sig256Z[indexWord( 4, 2 )] = sigZ.v0; - } - } - } else { - if ( shiftDist ) softfloat_add256M( sig256Z, sig256Z, sig256Z ); - if ( ! expDiff ) { - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - } else { - sig256C[indexWord( 4, 3 )] = sigC.v64; - sig256C[indexWord( 4, 2 )] = sigC.v0; - sig256C[indexWord( 4, 1 )] = 0; - sig256C[indexWord( 4, 0 )] = 0; - softfloat_shiftRightJam256M( sig256C, expDiff, sig256C ); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 8; - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ = softfloat_add128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); - } else { - softfloat_add256M( sig256Z, sig256C, sig256Z ); - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - } - if ( sigZ.v64 & UINT64_C( 0x0200000000000000 ) ) { - ++expZ; - shiftDist = 9; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - if ( expDiff < -1 ) { - sigZ = - softfloat_sub128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); - sigZExtra = - sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; - if ( sigZExtra ) { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); - } - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = 7; - } - goto shiftRightRoundPack; - } else { - sig256C[indexWord( 4, 3 )] = sigC.v64; - sig256C[indexWord( 4, 2 )] = sigC.v0; - sig256C[indexWord( 4, 1 )] = 0; - sig256C[indexWord( 4, 0 )] = 0; - softfloat_sub256M( sig256C, sig256Z, sig256Z ); - } - } else if ( ! expDiff ) { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, sigC.v64, sigC.v0 ); - if ( - ! (sigZ.v64 | sigZ.v0) && ! sig256Z[indexWord( 4, 1 )] - && ! sig256Z[indexWord( 4, 0 )] - ) { - goto completeCancellation; - } - sig256Z[indexWord( 4, 3 )] = sigZ.v64; - sig256Z[indexWord( 4, 2 )] = sigZ.v0; - if ( sigZ.v64 & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - softfloat_sub256M( zero256, sig256Z, sig256Z ); - } - } else { - softfloat_sub256M( sig256Z, sig256C, sig256Z ); - if ( 1 < expDiff ) { - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = 7; - } - goto sigZ; - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - sigZExtra = sig256Z[indexWord( 4, 1 )]; - sig256Z0 = sig256Z[indexWord( 4, 0 )]; - if ( sigZ.v64 ) { - if ( sig256Z0 ) sigZExtra |= 1; - } else { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = sigZExtra; - sigZExtra = sig256Z0; - if ( ! sigZ.v64 ) { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = sigZExtra; - sigZExtra = 0; - if ( ! sigZ.v64 ) { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = 0; - } - } - } - shiftDist = softfloat_countLeadingZeros64( sigZ.v64 ); - expZ += 7 - shiftDist; - shiftDist = 15 - shiftDist; - if ( 0 < shiftDist ) goto shiftRightRoundPack; - if ( shiftDist ) { - shiftDist = -shiftDist; - sigZ = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, shiftDist ); - x128 = softfloat_shortShiftLeft128( 0, sigZExtra, shiftDist ); - sigZ.v0 |= x128.v64; - sigZExtra = x128.v0; - } - goto roundPack; - } - sigZ: - sigZExtra = sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; - shiftRightRoundPack: - sigZExtra = (uint64_t) (sigZ.v0<<(64 - shiftDist)) | (sigZExtra != 0); - sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, shiftDist ); - roundPack: - return - softfloat_roundPackToF128( - signZ, expZ - 1, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - uiZ.v0 = 0; - if ( expC != 0x7FFF ) goto uiZ; - if ( sigC.v64 | sigC.v0 ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF128UI( uiZ.v64, uiZ.v0, uiC64, uiC0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ.v64 = uiC64; - uiZ.v0 = uiC0; - if ( ! (expC | sigC.v64 | sigC.v0) && (signZ != signC) ) { - completeCancellation: - uiZ.v64 = - packToF128UI64( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ.v0 = 0; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_mulAddF128M.c b/deps/SoftFloat-3e/source/s_mulAddF128M.c deleted file mode 100644 index f51fc71d28e3..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF128M.c +++ /dev/null @@ -1,382 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_mulAddF128M( - const uint32_t *aWPtr, - const uint32_t *bWPtr, - const uint32_t *cWPtr, - uint32_t *zWPtr, - uint_fast8_t op - ) -{ - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - uint32_t uiC96; - bool signC; - int32_t expC; - bool signProd, prodIsInfinite; - uint32_t *ptr, uiZ96, sigA[4]; - uint_fast8_t shiftDist; - uint32_t sigX[5]; - int32_t expProd; - uint32_t sigProd[8], wordSig; - bool doSub; - uint_fast8_t - (*addCarryMRoutinePtr)( - uint_fast8_t, - const uint32_t *, - const uint32_t *, - uint_fast8_t, - uint32_t * - ); - int32_t expDiff; - bool signZ; - int32_t expZ; - uint32_t *extSigPtr; - uint_fast8_t carry; - void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - uiC96 = cWPtr[indexWordHi( 4 )]; - signC = signF128UI96( uiC96 ) ^ (op == softfloat_mulAdd_subC); - expC = expF128UI96( uiC96 ); - signProd = - signF128UI96( uiA96 ) ^ signF128UI96( uiB96 ) - ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - prodIsInfinite = false; - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) { - goto propagateNaN_ZC; - } - ptr = (uint32_t *) aWPtr; - if ( ! (uint32_t) (uiA96<<1) ) goto possibleInvalidProd; - if ( ! (uint32_t) (uiB96<<1) ) { - ptr = (uint32_t *) bWPtr; - possibleInvalidProd: - if ( - ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )] - | ptr[indexWord( 4, 0 )]) - ) { - goto invalid; - } - } - prodIsInfinite = true; - } - if ( expC == 0x7FFF ) { - if ( - fracF128UI96( uiC96 ) - || (cWPtr[indexWord( 4, 2 )] | cWPtr[indexWord( 4, 1 )] - | cWPtr[indexWord( 4, 0 )]) - ) { - zWPtr[indexWordHi( 4 )] = 0; - goto propagateNaN_ZC; - } - if ( prodIsInfinite && (signProd != signC) ) goto invalid; - goto copyC; - } - if ( prodIsInfinite ) { - uiZ96 = packToF128UI96( signProd, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA ) { - sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000; - sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - } else { - expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA ); - if ( expA == -128 ) goto zeroProd; - } - if ( expB ) { - sigX[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000; - sigX[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )]; - sigX[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )]; - sigX[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )]; - } else { - expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigX ); - if ( expB == -128 ) goto zeroProd; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0x3FF0; - softfloat_mul128MTo256M( sigA, sigX, sigProd ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - wordSig = fracF128UI96( uiC96 ); - if ( expC ) { - --expC; - wordSig |= 0x00010000; - } - sigX[indexWordHi( 5 )] = wordSig; - sigX[indexWord( 5, 3 )] = cWPtr[indexWord( 4, 2 )]; - sigX[indexWord( 5, 2 )] = cWPtr[indexWord( 4, 1 )]; - sigX[indexWord( 5, 1 )] = cWPtr[indexWord( 4, 0 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - doSub = (signProd != signC); - addCarryMRoutinePtr = - doSub ? softfloat_addComplCarryM : softfloat_addCarryM; - expDiff = expProd - expC; - if ( expDiff <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signC; - expZ = expC; - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - if ( expDiff ) { - softfloat_shiftRightJam160M( extSigPtr, -expDiff, extSigPtr ); - } - carry = 0; - if ( doSub ) { - wordSig = extSigPtr[indexWordLo( 5 )]; - extSigPtr[indexWordLo( 5 )] = -wordSig; - carry = ! wordSig; - } - (*addCarryMRoutinePtr)( - 4, - &sigX[indexMultiwordHi( 5, 4 )], - extSigPtr + indexMultiwordHi( 5, 4 ), - carry, - extSigPtr + indexMultiwordHi( 5, 4 ) - ); - wordSig = extSigPtr[indexWordHi( 5 )]; - if ( ! expZ ) { - if ( wordSig & 0x80000000 ) { - signZ = ! signZ; - softfloat_negX160M( extSigPtr ); - wordSig = extSigPtr[indexWordHi( 5 )]; - } - goto checkCancellation; - } - if ( wordSig < 0x00010000 ) { - --expZ; - softfloat_add160M( extSigPtr, extSigPtr, extSigPtr ); - goto roundPack; - } - goto extSigReady_noCancellation; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signProd; - expZ = expProd; - sigX[indexWordLo( 5 )] = 0; - expDiff -= 128; - if ( 0 <= expDiff ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - if ( expDiff ) softfloat_shiftRightJam160M( sigX, expDiff, sigX ); - wordSig = sigX[indexWordLo( 5 )]; - carry = 0; - if ( doSub ) { - carry = ! wordSig; - wordSig = -wordSig; - } - carry = - (*addCarryMRoutinePtr)( - 4, - &sigProd[indexMultiwordLo( 8, 4 )], - &sigX[indexMultiwordHi( 5, 4 )], - carry, - &sigProd[indexMultiwordLo( 8, 4 )] - ); - sigProd[indexWord( 8, 2 )] |= wordSig; - ptr = &sigProd[indexWord( 8, 4 )]; - } else { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - shiftDist = expDiff & 31; - if ( shiftDist ) { - softfloat_shortShiftRight160M( sigX, shiftDist, sigX ); - } - expDiff >>= 5; - extSigPtr = - &sigProd[indexMultiwordLo( 8, 5 )] - wordIncr - + expDiff * -wordIncr; - carry = - (*addCarryMRoutinePtr)( 5, extSigPtr, sigX, doSub, extSigPtr ); - if ( expDiff == -4 ) { - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - wordSig = sigProd[indexWordHi( 8 )]; - if ( wordSig & 0x80000000 ) { - signZ = ! signZ; - softfloat_negX256M( sigProd ); - wordSig = sigProd[indexWordHi( 8 )]; - } - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - if ( wordSig ) goto expProdBigger_noWordShift; - wordSig = sigProd[indexWord( 8, 6 )]; - if ( 0x00040000 <= wordSig ) goto expProdBigger_noWordShift; - expZ -= 32; - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )] - wordIncr; - for (;;) { - if ( wordSig ) break; - wordSig = extSigPtr[indexWord( 5, 3 )]; - if ( 0x00040000 <= wordSig ) break; - expZ -= 32; - extSigPtr -= wordIncr; - if ( extSigPtr == &sigProd[indexMultiwordLo( 8, 5 )] ) { - goto checkCancellation; - } - } - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - ptr = extSigPtr + indexWordLo( 5 ); - do { - ptr -= wordIncr; - if ( *ptr ) { - extSigPtr[indexWordLo( 5 )] |= 1; - break; - } - } while ( ptr != &sigProd[indexWordLo( 8 )] ); - wordSig = extSigPtr[indexWordHi( 5 )]; - goto extSigReady; - } - ptr = extSigPtr + indexWordHi( 5 ) + wordIncr; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( carry != doSub ) { - if ( doSub ) { - do { - wordSig = *ptr; - *ptr = wordSig - 1; - ptr += wordIncr; - } while ( ! wordSig ); - } else { - do { - wordSig = *ptr + 1; - *ptr = wordSig; - ptr += wordIncr; - } while ( ! wordSig ); - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - expProdBigger_noWordShift: - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - wordSig = extSigPtr[indexWordHi( 5 )]; - } - extSigReady: - roundPackRoutinePtr = softfloat_normRoundPackMToF128M; - if ( wordSig < 0x00010000 ) goto doRoundPack; - extSigReady_noCancellation: - if ( 0x00020000 <= wordSig ) { - ++expZ; - softfloat_shortShiftRightJam160M( extSigPtr, 1, extSigPtr ); - } - roundPack: - roundPackRoutinePtr = softfloat_roundPackMToF128M; - doRoundPack: - (*roundPackRoutinePtr)( signZ, expZ, extSigPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - propagateNaN_ZC: - softfloat_propagateNaNF128M( zWPtr, cWPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - if ( - ! (uint32_t) (uiC96<<1) && (signProd != signC) - && ! cWPtr[indexWord( 4, 2 )] - && ! (cWPtr[indexWord( 4, 1 )] | cWPtr[indexWord( 4, 0 )]) - ) { - goto completeCancellation; - } - copyC: - zWPtr[indexWordHi( 4 )] = uiC96; - zWPtr[indexWord( 4, 2 )] = cWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = cWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = cWPtr[indexWord( 4, 0 )]; - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - checkCancellation: - if ( - wordSig - || (extSigPtr[indexWord( 5, 3 )] | extSigPtr[indexWord( 5, 2 )]) - || (extSigPtr[indexWord( 5, 1 )] | extSigPtr[indexWord( 5, 0 )]) - ) { - goto extSigReady; - } - completeCancellation: - uiZ96 = - packToF128UI96( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - diff --git a/deps/SoftFloat-3e/source/s_mulAddF16.c b/deps/SoftFloat-3e/source/s_mulAddF16.c deleted file mode 100644 index 3a684ac32c6d..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF16.c +++ /dev/null @@ -1,226 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t - softfloat_mulAddF16( - uint_fast16_t uiA, uint_fast16_t uiB, uint_fast16_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signC; - int_fast8_t expC; - uint_fast16_t sigC; - bool signProd; - uint_fast16_t magBits, uiZ; - struct exp8_sig16 normExpSig; - int_fast8_t expProd; - uint_fast32_t sigProd; - bool signZ; - int_fast8_t expZ; - uint_fast16_t sigZ; - int_fast8_t expDiff; - uint_fast32_t sig32Z, sig32C; - int_fast8_t shiftDist; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signC = signF16UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF16UI( uiC ); - sigC = fracF16UI( uiC ); - signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x1F ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0xE; - sigA = (sigA | 0x0400)<<4; - sigB = (sigB | 0x0400)<<4; - sigProd = (uint_fast32_t) sigA * sigB; - if ( sigProd < 0x20000000 ) { - --expProd; - sigProd <<= 1; - } - signZ = signProd; - if ( ! expC ) { - if ( ! sigC ) { - expZ = expProd - 1; - sigZ = sigProd>>15 | ((sigProd & 0x7FFF) != 0); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF16Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | 0x0400)<<3; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expProd - expC; - if ( signProd == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - expZ = expC; - sigZ = sigC + softfloat_shiftRightJam32( sigProd, 16 - expDiff ); - } else { - expZ = expProd; - sig32Z = - sigProd - + softfloat_shiftRightJam32( - (uint_fast32_t) sigC<<16, expDiff ); - sigZ = sig32Z>>16 | ((sig32Z & 0xFFFF) != 0 ); - } - if ( sigZ < 0x4000 ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig32C = (uint_fast32_t) sigC<<16; - if ( expDiff < 0 ) { - signZ = signC; - expZ = expC; - sig32Z = sig32C - softfloat_shiftRightJam32( sigProd, -expDiff ); - } else if ( ! expDiff ) { - expZ = expProd; - sig32Z = sigProd - sig32C; - if ( ! sig32Z ) goto completeCancellation; - if ( sig32Z & 0x80000000 ) { - signZ = ! signZ; - sig32Z = -sig32Z; - } - } else { - expZ = expProd; - sig32Z = sigProd - softfloat_shiftRightJam32( sig32C, expDiff ); - } - shiftDist = softfloat_countLeadingZeros32( sig32Z ) - 1; - expZ -= shiftDist; - shiftDist -= 16; - if ( shiftDist < 0 ) { - sigZ = - sig32Z>>(-shiftDist) - | ((uint32_t) (sig32Z<<(shiftDist & 31)) != 0); - } else { - sigZ = (uint_fast16_t) sig32Z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t - softfloat_mulAddF32( - uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signC; - int_fast16_t expC; - uint_fast32_t sigC; - bool signProd; - uint_fast32_t magBits, uiZ; - struct exp16_sig32 normExpSig; - int_fast16_t expProd; - uint_fast64_t sigProd; - bool signZ; - int_fast16_t expZ; - uint_fast32_t sigZ; - int_fast16_t expDiff; - uint_fast64_t sig64Z, sig64C; - int_fast8_t shiftDist; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signC = signF32UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF32UI( uiC ); - sigC = fracF32UI( uiC ); - signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0xFF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0x7E; - sigA = (sigA | 0x00800000)<<7; - sigB = (sigB | 0x00800000)<<7; - sigProd = (uint_fast64_t) sigA * sigB; - if ( sigProd < UINT64_C( 0x2000000000000000 ) ) { - --expProd; - sigProd <<= 1; - } - signZ = signProd; - if ( ! expC ) { - if ( ! sigC ) { - expZ = expProd - 1; - sigZ = softfloat_shortShiftRightJam64( sigProd, 31 ); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF32Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | 0x00800000)<<6; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expProd - expC; - if ( signProd == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - expZ = expC; - sigZ = sigC + softfloat_shiftRightJam64( sigProd, 32 - expDiff ); - } else { - expZ = expProd; - sig64Z = - sigProd - + softfloat_shiftRightJam64( - (uint_fast64_t) sigC<<32, expDiff ); - sigZ = softfloat_shortShiftRightJam64( sig64Z, 32 ); - } - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64C = (uint_fast64_t) sigC<<32; - if ( expDiff < 0 ) { - signZ = signC; - expZ = expC; - sig64Z = sig64C - softfloat_shiftRightJam64( sigProd, -expDiff ); - } else if ( ! expDiff ) { - expZ = expProd; - sig64Z = sigProd - sig64C; - if ( ! sig64Z ) goto completeCancellation; - if ( sig64Z & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - sig64Z = -sig64Z; - } - } else { - expZ = expProd; - sig64Z = sigProd - softfloat_shiftRightJam64( sig64C, expDiff ); - } - shiftDist = softfloat_countLeadingZeros64( sig64Z ) - 1; - expZ -= shiftDist; - shiftDist -= 32; - if ( shiftDist < 0 ) { - sigZ = softfloat_shortShiftRightJam64( sig64Z, -shiftDist ); - } else { - sigZ = (uint_fast32_t) sig64Z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t - softfloat_mulAddF64( - uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signC; - int_fast16_t expC; - uint_fast64_t sigC; - bool signZ; - uint_fast64_t magBits, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - struct uint128 sig128Z; - uint_fast64_t sigZ; - int_fast16_t expDiff; - struct uint128 sig128C; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF64UI( uiC ); - sigC = fracF64UI( uiC ); - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x7FF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FE; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<10; - sig128Z = softfloat_mul64To128( sigA, sigB ); - if ( sig128Z.v64 < UINT64_C( 0x2000000000000000 ) ) { - --expZ; - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); - } - if ( ! expC ) { - if ( ! sigC ) { - --expZ; - sigZ = sig128Z.v64<<1 | (sig128Z.v0 != 0); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF64Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<9; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - sig128Z.v64 = softfloat_shiftRightJam64( sig128Z.v64, -expDiff ); - } else { - sig128Z = - softfloat_shortShiftRightJam128( sig128Z.v64, sig128Z.v0, 1 ); - } - } else if ( expDiff ) { - sig128C = softfloat_shiftRightJam128( sigC, 0, expDiff ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ = (sigC + sig128Z.v64) | (sig128Z.v0 != 0); - } else { - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); - sigZ = sig128Z.v64 | (sig128Z.v0 != 0); - } - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - sig128Z = softfloat_sub128( sigC, 0, sig128Z.v64, sig128Z.v0 ); - } else if ( ! expDiff ) { - sig128Z.v64 = sig128Z.v64 - sigC; - if ( ! (sig128Z.v64 | sig128Z.v0) ) goto completeCancellation; - if ( sig128Z.v64 & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - sig128Z = softfloat_sub128( 0, 0, sig128Z.v64, sig128Z.v0 ); - } - } else { - sig128Z = - softfloat_sub128( - sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! sig128Z.v64 ) { - expZ -= 64; - sig128Z.v64 = sig128Z.v0; - sig128Z.v0 = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig128Z.v64 ) - 1; - expZ -= shiftDist; - if ( shiftDist < 0 ) { - sigZ = softfloat_shortShiftRightJam64( sig128Z.v64, -shiftDist ); - } else { - sig128Z = - softfloat_shortShiftLeft128( - sig128Z.v64, sig128Z.v0, shiftDist ); - sigZ = sig128Z.v64; - } - sigZ |= (sig128Z.v0 != 0); - } - roundPack: - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - if ( expC != 0x7FF ) goto uiZ; - if ( sigC ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ = uiC; - if ( ! (expC | sigC) && (signZ != signC) ) { - completeCancellation: - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#else - -float64_t - softfloat_mulAddF64( - uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint64_t sigA; - bool signB; - int_fast16_t expB; - uint64_t sigB; - bool signC; - int_fast16_t expC; - uint64_t sigC; - bool signZ; - uint64_t magBits, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t sig128Z[4]; - uint64_t sigZ; - int_fast16_t shiftDist, expDiff; - uint32_t sig128C[4]; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF64UI( uiC ); - sigC = fracF64UI( uiC ); - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x7FF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FE; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; - softfloat_mul64To128M( sigA, sigB, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; - shiftDist = 0; - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - shiftDist = -1; - } - if ( ! expC ) { - if ( ! sigC ) { - if ( shiftDist ) sigZ <<= 1; - goto sigZ; - } - normExpSig = softfloat_normSubnormalF64Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<10; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - shiftDist -= expDiff; - if ( shiftDist) { - sigZ = softfloat_shiftRightJam64( sigZ, shiftDist ); - } - } else { - if ( ! shiftDist ) { - softfloat_shortShiftRight128M( sig128Z, 1, sig128Z ); - } - } - } else { - if ( shiftDist ) softfloat_add128M( sig128Z, sig128Z, sig128Z ); - if ( ! expDiff ) { - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } else { - sig128C[indexWord( 4, 3 )] = sigC>>32; - sig128C[indexWord( 4, 2 )] = sigC; - sig128C[indexWord( 4, 1 )] = 0; - sig128C[indexWord( 4, 0 )] = 0; - softfloat_shiftRightJam128M( sig128C, expDiff, sig128C ); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ += sigC; - } else { - softfloat_add128M( sig128Z, sig128C, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { - ++expZ; - sigZ = softfloat_shortShiftRightJam64( sigZ, 1 ); - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - if ( expDiff < -1 ) { - sigZ = sigC - sigZ; - if ( - sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] - ) { - sigZ = (sigZ - 1) | 1; - } - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - sigZ <<= 1; - } - goto roundPack; - } else { - sig128C[indexWord( 4, 3 )] = sigC>>32; - sig128C[indexWord( 4, 2 )] = sigC; - sig128C[indexWord( 4, 1 )] = 0; - sig128C[indexWord( 4, 0 )] = 0; - softfloat_sub128M( sig128C, sig128Z, sig128Z ); - } - } else if ( ! expDiff ) { - sigZ -= sigC; - if ( - ! sigZ && ! sig128Z[indexWord( 4, 1 )] - && ! sig128Z[indexWord( 4, 0 )] - ) { - goto completeCancellation; - } - sig128Z[indexWord( 4, 3 )] = sigZ>>32; - sig128Z[indexWord( 4, 2 )] = sigZ; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - softfloat_negX128M( sig128Z ); - } - } else { - softfloat_sub128M( sig128Z, sig128C, sig128Z ); - if ( 1 < expDiff ) { - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - sigZ <<= 1; - } - goto sigZ; - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - shiftDist = 0; - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - if ( ! sigZ ) { - shiftDist = 64; - sigZ = - (uint64_t) sig128Z[indexWord( 4, 1 )]<<32 - | sig128Z[indexWord( 4, 0 )]; - } - shiftDist += softfloat_countLeadingZeros64( sigZ ) - 1; - if ( shiftDist ) { - expZ -= shiftDist; - softfloat_shiftLeft128M( sig128Z, shiftDist, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } - } - sigZ: - if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; - roundPack: - return softfloat_roundPackToF64( signZ, expZ - 1, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - if ( expC != 0x7FF ) goto uiZ; - if ( sigC ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ = uiC; - if ( ! (expC | sigC) && (signZ != signC) ) { - completeCancellation: - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_negXM.c b/deps/SoftFloat-3e/source/s_negXM.c deleted file mode 100644 index ec8c928861ca..000000000000 --- a/deps/SoftFloat-3e/source/s_negXM.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_negXM - -void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ) -{ - unsigned int index, lastIndex; - uint_fast8_t carry; - uint32_t word; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - carry = 1; - for (;;) { - word = ~zPtr[index] + carry; - zPtr[index] = word; - if ( index == lastIndex ) break; - index += wordIncr; - if ( word ) carry = 0; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_normExtF80SigM.c b/deps/SoftFloat-3e/source/s_normExtF80SigM.c deleted file mode 100644 index acc54dc63c8d..000000000000 --- a/deps/SoftFloat-3e/source/s_normExtF80SigM.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -int softfloat_normExtF80SigM( uint64_t *sigPtr ) -{ - uint64_t sig; - int_fast8_t shiftDist; - - sig = *sigPtr; - shiftDist = softfloat_countLeadingZeros64( sig ); - *sigPtr = sig< -#include -#include "platform.h" -#include "internals.h" - -void - softfloat_normRoundPackMToExtF80M( - bool sign, - int32_t exp, - uint32_t *extSigPtr, - uint_fast8_t roundingPrecision, - struct extFloat80M *zSPtr - ) -{ - int_fast16_t shiftDist; - uint32_t wordSig; - - shiftDist = 0; - wordSig = extSigPtr[indexWord( 3, 2 )]; - if ( ! wordSig ) { - shiftDist = 32; - wordSig = extSigPtr[indexWord( 3, 1 )]; - if ( ! wordSig ) { - shiftDist = 64; - wordSig = extSigPtr[indexWord( 3, 0 )]; - if ( ! wordSig ) { - zSPtr->signExp = packToExtF80UI64( sign, 0 ); - zSPtr->signif = 0; - return; - } - } - } - shiftDist += softfloat_countLeadingZeros32( wordSig ); - if ( shiftDist ) { - exp -= shiftDist; - softfloat_shiftLeft96M( extSigPtr, shiftDist, extSigPtr ); - } - softfloat_roundPackMToExtF80M( - sign, exp, extSigPtr, roundingPrecision, zSPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c b/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c deleted file mode 100644 index 309455998c7f..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -void - softfloat_normRoundPackMToF128M( - bool sign, int32_t exp, uint32_t *extSigPtr, uint32_t *zWPtr ) -{ - const uint32_t *ptr; - int_fast16_t shiftDist; - uint32_t wordSig; - - ptr = extSigPtr + indexWordHi( 5 ); - shiftDist = 0; - for (;;) { - wordSig = *ptr; - if ( wordSig ) break; - shiftDist += 32; - if ( 160 <= shiftDist ) { - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, 0, 0 ); - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - ptr -= wordIncr; - } - shiftDist += softfloat_countLeadingZeros32( wordSig ) - 15; - if ( shiftDist ) { - exp -= shiftDist; - softfloat_shiftLeft160M( extSigPtr, shiftDist, extSigPtr ); - } - softfloat_roundPackMToF128M( sign, exp, extSigPtr, zWPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c b/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c deleted file mode 100644 index 76e791d911a3..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -extFloat80_t - softfloat_normRoundPackToExtF80( - bool sign, - int_fast32_t exp, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingPrecision - ) -{ - int_fast8_t shiftDist; - struct uint128 sig128; - - if ( ! sig ) { - exp -= 64; - sig = sigExtra; - sigExtra = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig ); - exp -= shiftDist; - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig, sigExtra, shiftDist ); - sig = sig128.v64; - sigExtra = sig128.v0; - } - return - softfloat_roundPackToExtF80( - sign, exp, sig, sigExtra, roundingPrecision ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToF128.c b/deps/SoftFloat-3e/source/s_normRoundPackToF128.c deleted file mode 100644 index 67f5b4349078..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToF128.c +++ /dev/null @@ -1,81 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -float128_t - softfloat_normRoundPackToF128( - bool sign, int_fast32_t exp, uint_fast64_t sig64, uint_fast64_t sig0 ) -{ - int_fast8_t shiftDist; - struct uint128 sig128; - union ui128_f128 uZ; - uint_fast64_t sigExtra; - struct uint128_extra sig128Extra; - - if ( ! sig64 ) { - exp -= 64; - sig64 = sig0; - sig0 = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig64 ) - 15; - exp -= shiftDist; - if ( 0 <= shiftDist ) { - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - if ( (uint32_t) exp < 0x7FFD ) { - uZ.ui.v64 = packToF128UI64( sign, sig64 | sig0 ? exp : 0, sig64 ); - uZ.ui.v0 = sig0; - return uZ.f; - } - sigExtra = 0; - } else { - sig128Extra = - softfloat_shortShiftRightJam128Extra( sig64, sig0, 0, -shiftDist ); - sig64 = sig128Extra.v.v64; - sig0 = sig128Extra.v.v0; - sigExtra = sig128Extra.extra; - } - return softfloat_roundPackToF128( sign, exp, sig64, sig0, sigExtra ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToF16.c b/deps/SoftFloat-3e/source/s_normRoundPackToF16.c deleted file mode 100644 index 1d184d58ba9e..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToF16.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -float16_t - softfloat_normRoundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) -{ - int_fast8_t shiftDist; - union ui16_f16 uZ; - - shiftDist = softfloat_countLeadingZeros16( sig ) - 1; - exp -= shiftDist; - if ( (4 <= shiftDist) && ((unsigned int) exp < 0x1D) ) { - uZ.ui = packToF16UI( sign, sig ? exp : 0, sig<<(shiftDist - 4) ); - return uZ.f; - } else { - return softfloat_roundPackToF16( sign, exp, sig< -#include -#include "platform.h" -#include "internals.h" - -float32_t - softfloat_normRoundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) -{ - int_fast8_t shiftDist; - union ui32_f32 uZ; - - shiftDist = softfloat_countLeadingZeros32( sig ) - 1; - exp -= shiftDist; - if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) { - uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7) ); - return uZ.f; - } else { - return softfloat_roundPackToF32( sign, exp, sig< -#include -#include "platform.h" -#include "internals.h" - -float64_t - softfloat_normRoundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - union ui64_f64 uZ; - - shiftDist = softfloat_countLeadingZeros64( sig ) - 1; - exp -= shiftDist; - if ( (10 <= shiftDist) && ((unsigned int) exp < 0x7FD) ) { - uZ.ui = packToF64UI( sign, sig ? exp : 0, sig<<(shiftDist - 10) ); - return uZ.f; - } else { - return softfloat_roundPackToF64( sign, exp, sig< -#include "platform.h" -#include "internals.h" - -struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - struct exp32_sig64 z; - - shiftDist = softfloat_countLeadingZeros64( sig ); - z.exp = -shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp32_sig128 - softfloat_normSubnormalF128Sig( uint_fast64_t sig64, uint_fast64_t sig0 ) -{ - int_fast8_t shiftDist; - struct exp32_sig128 z; - - if ( ! sig64 ) { - shiftDist = softfloat_countLeadingZeros64( sig0 ) - 15; - z.exp = -63 - shiftDist; - if ( shiftDist < 0 ) { - z.sig.v64 = sig0>>-shiftDist; - z.sig.v0 = sig0<<(shiftDist & 63); - } else { - z.sig.v64 = sig0< -#include "platform.h" -#include "internals.h" - -int softfloat_normSubnormalF128SigM( uint32_t *sigPtr ) -{ - const uint32_t *ptr; - int_fast16_t shiftDist; - uint32_t wordSig; - - ptr = sigPtr + indexWordHi( 4 ); - shiftDist = 0; - for (;;) { - wordSig = *ptr; - if ( wordSig ) break; - shiftDist += 32; - if ( 128 <= shiftDist ) return 1; - ptr -= wordIncr; - } - shiftDist += softfloat_countLeadingZeros32( wordSig ) - 15; - if ( shiftDist ) softfloat_shiftLeft128M( sigPtr, shiftDist, sigPtr ); - return 1 - shiftDist; - -} - diff --git a/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c b/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c deleted file mode 100644 index bb92adfea56a..000000000000 --- a/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t sig ) -{ - int_fast8_t shiftDist; - struct exp8_sig16 z; - - shiftDist = softfloat_countLeadingZeros16( sig ) - 5; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t sig ) -{ - int_fast8_t shiftDist; - struct exp16_sig32 z; - - shiftDist = softfloat_countLeadingZeros32( sig ) - 8; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - struct exp16_sig64 z; - - shiftDist = softfloat_countLeadingZeros64( sig ) - 11; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_remStepMBy32 - -void - softfloat_remStepMBy32( - uint_fast8_t size_words, - const uint32_t *remPtr, - uint_fast8_t dist, - const uint32_t *bPtr, - uint32_t q, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint64_t dwordProd; - uint32_t wordRem, wordShiftedRem, wordProd; - uint_fast8_t uNegDist, borrow; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - dwordProd = (uint64_t) bPtr[index] * q; - wordRem = remPtr[index]; - wordShiftedRem = wordRem<>(uNegDist & 31); - index += wordIncr; - dwordProd = (uint64_t) bPtr[index] * q + (dwordProd>>32); - wordRem = remPtr[index]; - wordShiftedRem |= wordRem< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - softfloat_roundMToI64( - bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) -{ - uint64_t sig; - uint32_t sigExtra; - union { uint64_t ui; int64_t i; } uZ; - int64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( 0x80000000 <= sigExtra ) goto increment; - } else { - if ( - sigExtra - && (sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max)) - ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == 0x80000000) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - uZ.ui = sign ? -sig : sig; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundMToUI64.c b/deps/SoftFloat-3e/source/s_roundMToUI64.c deleted file mode 100644 index 196f53735f5b..000000000000 --- a/deps/SoftFloat-3e/source/s_roundMToUI64.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - softfloat_roundMToUI64( - bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) -{ - uint64_t sig; - uint32_t sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( 0x80000000 <= sigExtra ) goto increment; - } else { - if ( sign ) { - if ( !(sig | sigExtra) ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( (roundingMode == softfloat_round_max) && sigExtra ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == 0x80000000) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - } - if ( sign && sig ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sig |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sig; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c b/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c deleted file mode 100644 index 08620159f014..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c +++ /dev/null @@ -1,256 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -void - softfloat_roundPackMToExtF80M( - bool sign, - int32_t exp, - uint32_t *extSigPtr, - uint_fast8_t roundingPrecision, - struct extFloat80M *zSPtr - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint64_t sig, roundIncrement, roundMask, roundBits; - bool isTiny; - uint32_t sigExtra; - bool doIncrement; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - if ( roundingPrecision == 80 ) goto precision80; - if ( roundingPrecision == 64 ) { - roundIncrement = UINT64_C( 0x0000000000000400 ); - roundMask = UINT64_C( 0x00000000000007FF ); - } else if ( roundingPrecision == 32 ) { - roundIncrement = UINT64_C( 0x0000008000000000 ); - roundMask = UINT64_C( 0x000000FFFFFFFFFF ); - } else { - goto precision80; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? roundMask - : 0; - } - roundBits = sig & roundMask; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || (sig <= (uint64_t) (sig + roundIncrement)); - sig = softfloat_shiftRightJam64( sig, 1 - exp ); - roundBits = sig & roundMask; - if ( roundBits ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= roundMask + 1; - } -#endif - } - sig += roundIncrement; - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) - ) { - goto overflow; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig = (sig & ~roundMask) | (roundMask + 1); - goto packReturn; - } -#endif - } - sig += roundIncrement; - if ( sig < roundIncrement ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - precision80: - sigExtra = extSigPtr[indexWordLo( 3 )]; - doIncrement = (0x80000000 <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || ! doIncrement - || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); - softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr ); - exp = 0; - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( sigExtra ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - doIncrement = (0x80000000 <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - if ( doIncrement ) { - ++sig; - sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - } - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - roundMask = 0; - overflow: - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - exp = 0x7FFF; - sig = UINT64_C( 0x8000000000000000 ); - } else { - exp = 0x7FFE; - sig = ~roundMask; - } - goto packReturn; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - ++sig; - if ( ! sig ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } else { - sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - zSPtr->signExp = packToExtF80UI64( sign, exp ); - zSPtr->signif = sig; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackMToF128M.c b/deps/SoftFloat-3e/source/s_roundPackMToF128M.c deleted file mode 100644 index 22591b8356b4..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackMToF128M.c +++ /dev/null @@ -1,178 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -void - softfloat_roundPackMToF128M( - bool sign, int32_t exp, uint32_t *extSigPtr, uint32_t *zWPtr ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint32_t sigExtra; - bool doIncrement, isTiny; - static const uint32_t maxSig[4] = - INIT_UINTM4( 0x0001FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ); - uint32_t ui, uj; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - sigExtra = extSigPtr[indexWordLo( 5 )]; - doIncrement = (0x80000000 <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < -1) - || ! doIncrement - || (softfloat_compare128M( - extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) - < 0); - softfloat_shiftRightJam160M( extSigPtr, -exp, extSigPtr ); - exp = 0; - sigExtra = extSigPtr[indexWordLo( 5 )]; - if ( isTiny && sigExtra ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - doIncrement = (0x80000000 <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - } else if ( - (0x7FFD < exp) - || ((exp == 0x7FFD) && doIncrement - && (softfloat_compare128M( - extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) - == 0)) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - ui = packToF128UI96( sign, 0x7FFF, 0 ); - uj = 0; - } else { - ui = packToF128UI96( sign, 0x7FFE, 0x0000FFFF ); - uj = 0xFFFFFFFF; - } - zWPtr[indexWordHi( 4 )] = ui; - zWPtr[indexWord( 4, 2 )] = uj; - zWPtr[indexWord( 4, 1 )] = uj; - zWPtr[indexWord( 4, 0 )] = uj; - return; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uj = extSigPtr[indexWord( 5, 1 )]; - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - uj |= 1; - goto noIncrementPackReturn; - } -#endif - } - if ( doIncrement ) { - ++uj; - if ( uj ) { - if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) uj &= ~1; - zWPtr[indexWord( 4, 2 )] = extSigPtr[indexWord( 5, 3 )]; - zWPtr[indexWord( 4, 1 )] = extSigPtr[indexWord( 5, 2 )]; - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - } else { - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWord( 5, 2 )] + 1; - zWPtr[indexWord( 4, 1 )] = ui; - uj = extSigPtr[indexWord( 5, 3 )]; - if ( ui ) { - zWPtr[indexWord( 4, 2 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - } else { - ++uj; - zWPtr[indexWord( 4, 2 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - if ( ! uj ) ++ui; - } - } - } else { - noIncrementPackReturn: - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWord( 5, 2 )]; - zWPtr[indexWord( 4, 1 )] = ui; - uj |= ui; - ui = extSigPtr[indexWord( 5, 3 )]; - zWPtr[indexWord( 4, 2 )] = ui; - uj |= ui; - ui = extSigPtr[indexWordHi( 5 )]; - uj |= ui; - if ( ! uj ) exp = 0; - } - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp, ui ); - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToExtF80.c b/deps/SoftFloat-3e/source/s_roundPackToExtF80.c deleted file mode 100644 index 0cc7af9851ba..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToExtF80.c +++ /dev/null @@ -1,256 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t - softfloat_roundPackToExtF80( - bool sign, - int_fast32_t exp, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingPrecision - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast64_t roundIncrement, roundMask, roundBits; - bool isTiny, doIncrement; - struct uint64_extra sig64Extra; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - if ( roundingPrecision == 80 ) goto precision80; - if ( roundingPrecision == 64 ) { - roundIncrement = UINT64_C( 0x0000000000000400 ); - roundMask = UINT64_C( 0x00000000000007FF ); - } else if ( roundingPrecision == 32 ) { - roundIncrement = UINT64_C( 0x0000008000000000 ); - roundMask = UINT64_C( 0x000000FFFFFFFFFF ); - } else { - goto precision80; - } - sig |= (sigExtra != 0); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? roundMask - : 0; - } - roundBits = sig & roundMask; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || (sig <= (uint64_t) (sig + roundIncrement)); - sig = softfloat_shiftRightJam64( sig, 1 - exp ); - roundBits = sig & roundMask; - if ( roundBits ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= roundMask + 1; - } -#endif - } - sig += roundIncrement; - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) - ) { - goto overflow; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig = (sig & ~roundMask) | (roundMask + 1); - goto packReturn; - } -#endif - } - sig = (uint64_t) (sig + roundIncrement); - if ( sig < roundIncrement ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - precision80: - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || ! doIncrement - || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); - sig64Extra = - softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); - exp = 0; - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - if ( sigExtra ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - if ( doIncrement ) { - ++sig; - sig &= - ~(uint_fast64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - } - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - roundMask = 0; - overflow: - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - exp = 0x7FFF; - sig = UINT64_C( 0x8000000000000000 ); - } else { - exp = 0x7FFE; - sig = ~roundMask; - } - goto packReturn; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - ++sig; - if ( ! sig ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } else { - sig &= - ~(uint_fast64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uZ.s.signExp = packToExtF80UI64( sign, exp ); - uZ.s.signif = sig; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF128.c b/deps/SoftFloat-3e/source/s_roundPackToF128.c deleted file mode 100644 index 41584316a4af..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF128.c +++ /dev/null @@ -1,171 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t - softfloat_roundPackToF128( - bool sign, - int_fast32_t exp, - uint_fast64_t sig64, - uint_fast64_t sig0, - uint_fast64_t sigExtra - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven, doIncrement, isTiny; - struct uint128_extra sig128Extra; - uint_fast64_t uiZ64, uiZ0; - struct uint128 sig128; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < -1) - || ! doIncrement - || softfloat_lt128( - sig64, - sig0, - UINT64_C( 0x0001FFFFFFFFFFFF ), - UINT64_C( 0xFFFFFFFFFFFFFFFF ) - ); - sig128Extra = - softfloat_shiftRightJam128Extra( sig64, sig0, sigExtra, -exp ); - sig64 = sig128Extra.v.v64; - sig0 = sig128Extra.v.v0; - sigExtra = sig128Extra.extra; - exp = 0; - if ( isTiny && sigExtra ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - } else if ( - (0x7FFD < exp) - || ((exp == 0x7FFD) - && softfloat_eq128( - sig64, - sig0, - UINT64_C( 0x0001FFFFFFFFFFFF ), - UINT64_C( 0xFFFFFFFFFFFFFFFF ) - ) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - uiZ64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ0 = 0; - } else { - uiZ64 = - packToF128UI64( - sign, 0x7FFE, UINT64_C( 0x0000FFFFFFFFFFFF ) ); - uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); - } - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig0 |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - sig128 = softfloat_add128( sig64, sig0, 0, 1 ); - sig64 = sig128.v64; - sig0 = - sig128.v0 - & ~(uint64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - } else { - if ( ! (sig64 | sig0) ) exp = 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ64 = packToF128UI64( sign, exp, sig64 ); - uiZ0 = sig0; - uiZ: - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF16.c b/deps/SoftFloat-3e/source/s_roundPackToF16.c deleted file mode 100644 index 2dde55bb40a9..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF16.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t - softfloat_roundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast8_t roundIncrement, roundBits; - bool isTiny; - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x8; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0xF - : 0; - } - roundBits = sig & 0xF; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x1D <= (unsigned int) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) || (sig + roundIncrement < 0x8000); - sig = softfloat_shiftRightJam32( sig, -exp ); - exp = 0; - roundBits = sig & 0xF; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( (0x1D < exp) || (0x8000 <= sig + roundIncrement) ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF16UI( sign, 0x1F, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>4; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast16_t) (! (roundBits ^ 8) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF16UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF32.c b/deps/SoftFloat-3e/source/s_roundPackToF32.c deleted file mode 100644 index a69b8d4d7022..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF32.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t - softfloat_roundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast8_t roundIncrement, roundBits; - bool isTiny; - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x40; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0x7F - : 0; - } - roundBits = sig & 0x7F; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0xFD <= (unsigned int) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) || (sig + roundIncrement < 0x80000000); - sig = softfloat_shiftRightJam32( sig, -exp ); - exp = 0; - roundBits = sig & 0x7F; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( (0xFD < exp) || (0x80000000 <= sig + roundIncrement) ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF32UI( sign, 0xFF, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>7; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF32UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF64.c b/deps/SoftFloat-3e/source/s_roundPackToF64.c deleted file mode 100644 index f7f3abff52e4..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF64.c +++ /dev/null @@ -1,117 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t - softfloat_roundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast16_t roundIncrement, roundBits; - bool isTiny; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x200; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0x3FF - : 0; - } - roundBits = sig & 0x3FF; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FD <= (uint16_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) - || (sig + roundIncrement < UINT64_C( 0x8000000000000000 )); - sig = softfloat_shiftRightJam64( sig, -exp ); - exp = 0; - roundBits = sig & 0x3FF; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( - (0x7FD < exp) - || (UINT64_C( 0x8000000000000000 ) <= sig + roundIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF64UI( sign, 0x7FF, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>10; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast64_t) (! (roundBits ^ 0x200) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF64UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToI32.c b/deps/SoftFloat-3e/source/s_roundToI32.c deleted file mode 100644 index a3e727dc70e3..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToI32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t - softfloat_roundToI32( - bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) -{ - uint_fast16_t roundIncrement, roundBits; - uint_fast32_t sig32; - union { uint32_t ui; int32_t i; } uZ; - int_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundIncrement = 0x800; - if ( - (roundingMode != softfloat_round_near_maxMag) - && (roundingMode != softfloat_round_near_even) - ) { - roundIncrement = 0; - if ( - sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max) - ) { - roundIncrement = 0xFFF; - } - } - roundBits = sig & 0xFFF; - sig += roundIncrement; - if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; - sig32 = sig>>12; - if ( - (roundBits == 0x800) && (roundingMode == softfloat_round_near_even) - ) { - sig32 &= ~(uint_fast32_t) 1; - } - uZ.ui = sign ? -sig32 : sig32; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( roundBits ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i32_fromNegOverflow : i32_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToI64.c b/deps/SoftFloat-3e/source/s_roundToI64.c deleted file mode 100644 index 773c82cfc253..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToI64.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - softfloat_roundToI64( - bool sign, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingMode, - bool exact - ) -{ - union { uint64_t ui; int64_t i; } uZ; - int_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( UINT64_C( 0x8000000000000000 ) <= sigExtra ) goto increment; - } else { - if ( - sigExtra - && (sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max)) - ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == UINT64_C( 0x8000000000000000 )) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - uZ.ui = sign ? -sig : sig; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToUI32.c b/deps/SoftFloat-3e/source/s_roundToUI32.c deleted file mode 100644 index 059e231e2edd..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToUI32.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - softfloat_roundToUI32( - bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) -{ - uint_fast16_t roundIncrement, roundBits; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundIncrement = 0x800; - if ( - (roundingMode != softfloat_round_near_maxMag) - && (roundingMode != softfloat_round_near_even) - ) { - roundIncrement = 0; - if ( sign ) { - if ( !sig ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( roundingMode == softfloat_round_max ) roundIncrement = 0xFFF; - } - } - roundBits = sig & 0xFFF; - sig += roundIncrement; - if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; - z = sig>>12; - if ( - (roundBits == 0x800) && (roundingMode == softfloat_round_near_even) - ) { - z &= ~(uint_fast32_t) 1; - } - if ( sign && z ) goto invalid; - if ( roundBits ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToUI64.c b/deps/SoftFloat-3e/source/s_roundToUI64.c deleted file mode 100644 index 856ad97929f1..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToUI64.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - softfloat_roundToUI64( - bool sign, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingMode, - bool exact - ) -{ - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( UINT64_C( 0x8000000000000000 ) <= sigExtra ) goto increment; - } else { - if ( sign ) { - if ( !(sig | sigExtra) ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( (roundingMode == softfloat_round_max) && sigExtra ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == UINT64_C( 0x8000000000000000 )) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - } - if ( sign && sig ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sig |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sig; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_shiftLeftM.c b/deps/SoftFloat-3e/source/s_shiftLeftM.c deleted file mode 100644 index 71a309919919..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftLeftM.c +++ /dev/null @@ -1,91 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftLeftM - -#define softfloat_shiftLeftM softfloat_shiftLeftM -#include "primitives.h" - -void - softfloat_shiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordDist; - uint_fast8_t innerDist; - uint32_t *destPtr; - uint_fast8_t i; - - wordDist = dist>>5; - if ( wordDist < size_words ) { - aPtr += indexMultiwordLoBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftLeftM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordHiBut( size_words, wordDist ) - ); - if ( ! wordDist ) return; - } else { - aPtr += indexWordHi( size_words - wordDist ); - destPtr = zPtr + indexWordHi( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *destPtr = *aPtr; - aPtr -= wordIncr; - destPtr -= wordIncr; - } - } - zPtr += indexMultiwordLo( size_words, wordDist ); - } else { - wordDist = size_words; - } - do { - *zPtr++ = 0; - --wordDist; - } while ( wordDist ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c b/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c deleted file mode 100644 index fa4976c8e771..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -int - softfloat_shiftNormSigF128M( - const uint32_t *wPtr, uint_fast8_t shiftDist, uint32_t *sigPtr ) -{ - uint32_t wordSig; - int32_t exp; - uint32_t leadingBit; - - wordSig = wPtr[indexWordHi( 4 )]; - exp = expF128UI96( wordSig ); - if ( exp ) { - softfloat_shortShiftLeft128M( wPtr, shiftDist, sigPtr ); - leadingBit = 0x00010000< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam128 - -struct uint128 - softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ) -{ - uint_fast8_t u8NegDist; - struct uint128 z; - - if ( dist < 64 ) { - u8NegDist = -dist; - z.v64 = a64>>dist; - z.v0 = - a64<<(u8NegDist & 63) | a0>>dist - | ((uint64_t) (a0<<(u8NegDist & 63)) != 0); - } else { - z.v64 = 0; - z.v0 = - (dist < 127) - ? a64>>(dist & 63) - | (((a64 & (((uint_fast64_t) 1<<(dist & 63)) - 1)) | a0) - != 0) - : ((a64 | a0) != 0); - } - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c b/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c deleted file mode 100644 index 75722887bdf7..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c +++ /dev/null @@ -1,77 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam128Extra - -struct uint128_extra - softfloat_shiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ) -{ - uint_fast8_t u8NegDist; - struct uint128_extra z; - - u8NegDist = -dist; - if ( dist < 64 ) { - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(u8NegDist & 63) | a0>>dist; - z.extra = a0<<(u8NegDist & 63); - } else { - z.v.v64 = 0; - if ( dist == 64 ) { - z.v.v0 = a64; - z.extra = a0; - } else { - extra |= a0; - if ( dist < 128 ) { - z.v.v0 = a64>>(dist & 63); - z.extra = a64<<(u8NegDist & 63); - } else { - z.v.v0 = 0; - z.extra = (dist == 128) ? a64 : (a64 != 0); - } - } - } - z.extra |= (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam256M.c b/deps/SoftFloat-3e/source/s_shiftRightJam256M.c deleted file mode 100644 index 433870a81767..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam256M.c +++ /dev/null @@ -1,126 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam256M - -static - void - softfloat_shortShiftRightJamM( - uint_fast8_t size_words, - const uint64_t *aPtr, - uint_fast8_t dist, - uint64_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint64_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - wordA = aPtr[index]; - partWordZ = wordA>>dist; - if ( partWordZ<>dist; - } - zPtr[index] = partWordZ; - -} - -void - softfloat_shiftRightJam256M( - const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ) -{ - uint64_t wordJam; - uint_fast32_t wordDist; - uint64_t *ptr; - uint_fast8_t i, innerDist; - - wordJam = 0; - wordDist = dist>>6; - if ( wordDist ) { - if ( 4 < wordDist ) wordDist = 4; - ptr = (uint64_t *) (aPtr + indexMultiwordLo( 4, wordDist )); - i = wordDist; - do { - wordJam = *ptr++; - if ( wordJam ) break; - --i; - } while ( i ); - ptr = zPtr; - } - if ( wordDist < 4 ) { - aPtr += indexMultiwordHiBut( 4, wordDist ); - innerDist = dist & 63; - if ( innerDist ) { - softfloat_shortShiftRightJamM( - 4 - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( 4, wordDist ) - ); - if ( ! wordDist ) goto wordJam; - } else { - aPtr += indexWordLo( 4 - wordDist ); - ptr = zPtr + indexWordLo( 4 ); - for ( i = 4 - wordDist; i; --i ) { - *ptr = *aPtr; - aPtr += wordIncr; - ptr += wordIncr; - } - } - ptr = zPtr + indexMultiwordHi( 4, wordDist ); - } - do { - *ptr++ = 0; - --wordDist; - } while ( wordDist ); - wordJam: - if ( wordJam ) zPtr[indexWordLo( 4 )] |= 1; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam32.c b/deps/SoftFloat-3e/source/s_shiftRightJam32.c deleted file mode 100644 index 2533fcd95621..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam32.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJam32 - -uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ) -{ - - return - (dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam64.c b/deps/SoftFloat-3e/source/s_shiftRightJam64.c deleted file mode 100644 index 4b40e3de68c0..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam64.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJam64 - -uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) -{ - - return - (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c b/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c deleted file mode 100644 index b93fad39c944..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam64Extra - -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ) -{ - struct uint64_extra z; - - if ( dist < 64 ) { - z.v = a>>dist; - z.extra = a<<(-dist & 63); - } else { - z.v = 0; - z.extra = (dist == 64) ? a : (a != 0); - } - z.extra |= (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJamM.c b/deps/SoftFloat-3e/source/s_shiftRightJamM.c deleted file mode 100644 index edf5f956b9d5..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJamM.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJamM - -#define softfloat_shiftRightJamM softfloat_shiftRightJamM -#include "primitives.h" - -void - softfloat_shiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordJam, wordDist, *ptr; - uint_fast8_t i, innerDist; - - wordJam = 0; - wordDist = dist>>5; - if ( wordDist ) { - if ( size_words < wordDist ) wordDist = size_words; - ptr = (uint32_t *) (aPtr + indexMultiwordLo( size_words, wordDist )); - i = wordDist; - do { - wordJam = *ptr++; - if ( wordJam ) break; - --i; - } while ( i ); - ptr = zPtr; - } - if ( wordDist < size_words ) { - aPtr += indexMultiwordHiBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftRightJamM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( size_words, wordDist ) - ); - if ( ! wordDist ) goto wordJam; - } else { - aPtr += indexWordLo( size_words - wordDist ); - ptr = zPtr + indexWordLo( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *ptr = *aPtr; - aPtr += wordIncr; - ptr += wordIncr; - } - } - ptr = zPtr + indexMultiwordHi( size_words, wordDist ); - } - do { - *ptr++ = 0; - --wordDist; - } while ( wordDist ); - wordJam: - if ( wordJam ) zPtr[indexWordLo( size_words )] |= 1; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightM.c b/deps/SoftFloat-3e/source/s_shiftRightM.c deleted file mode 100644 index 00265ea238e2..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightM.c +++ /dev/null @@ -1,91 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightM - -#define softfloat_shiftRightM softfloat_shiftRightM -#include "primitives.h" - -void - softfloat_shiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordDist; - uint_fast8_t innerDist; - uint32_t *destPtr; - uint_fast8_t i; - - wordDist = dist>>5; - if ( wordDist < size_words ) { - aPtr += indexMultiwordHiBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftRightM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( size_words, wordDist ) - ); - if ( ! wordDist ) return; - } else { - aPtr += indexWordLo( size_words - wordDist ); - destPtr = zPtr + indexWordLo( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *destPtr = *aPtr; - aPtr += wordIncr; - destPtr += wordIncr; - } - } - zPtr += indexMultiwordHi( size_words, wordDist ); - } else { - wordDist = size_words; - } - do { - *zPtr++ = 0; - --wordDist; - } while ( wordDist ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftLeft128.c b/deps/SoftFloat-3e/source/s_shortShiftLeft128.c deleted file mode 100644 index 7513bc627288..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftLeft128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeft128 - -struct uint128 - softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - - z.v64 = a64<>(-dist & 63); - z.v0 = a0< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeft64To96M - -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) -{ - - zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; - zPtr[indexWord( 3, 2 )] = a>>32; - zPtr[indexWord( 3, 1 )] = a; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftLeftM.c b/deps/SoftFloat-3e/source/s_shortShiftLeftM.c deleted file mode 100644 index 48e6e03b542f..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftLeftM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeftM - -void - softfloat_shortShiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordHi( size_words ); - lastIndex = indexWordLo( size_words ); - partWordZ = aPtr[index]<>(uNegDist & 31); - index -= wordIncr; - partWordZ = wordA< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRight128 - -struct uint128 - softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - - z.v64 = a64>>dist; - z.v0 = a64<<(-dist & 63) | a0>>dist; - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c b/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c deleted file mode 100644 index bc441c731afe..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightExtendM - -void - softfloat_shortShiftRightExtendM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int indexA, lastIndexA; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - indexA = indexWordLo( size_words ); - lastIndexA = indexWordHi( size_words ); - zPtr += indexWordLo( size_words + 1 ); - partWordZ = 0; - for (;;) { - wordA = aPtr[indexA]; - *zPtr = wordA<<(uNegDist & 31) | partWordZ; - zPtr += wordIncr; - partWordZ = wordA>>dist; - if ( indexA == lastIndexA ) break; - indexA += wordIncr; - } - *zPtr = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c deleted file mode 100644 index 76008722bf90..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam128 - -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - uint_fast8_t uNegDist; - struct uint128 z; - - uNegDist = -dist; - z.v64 = a64>>dist; - z.v0 = - a64<<(uNegDist & 63) | a0>>dist - | ((uint64_t) (a0<<(uNegDist & 63)) != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c deleted file mode 100644 index b0774401d65b..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam128Extra - -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) -{ - uint_fast8_t uNegDist; - struct uint128_extra z; - - uNegDist = -dist; - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(uNegDist & 63) | a0>>dist; - z.extra = a0<<(uNegDist & 63) | (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c deleted file mode 100644 index d3044c853752..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c +++ /dev/null @@ -1,50 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shortShiftRightJam64 - -uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) -{ - - return a>>dist | ((a & (((uint_fast64_t) 1< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam64Extra - -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ) -{ - struct uint64_extra z; - - z.v = a>>dist; - z.extra = a<<(-dist & 63) | (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c b/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c deleted file mode 100644 index b567e482a8ae..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJamM - -void - softfloat_shortShiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - wordA = aPtr[index]; - partWordZ = wordA>>dist; - if ( partWordZ<>dist; - } - zPtr[index] = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightM.c b/deps/SoftFloat-3e/source/s_shortShiftRightM.c deleted file mode 100644 index 54e0071c7bf4..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightM - -void - softfloat_shortShiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - partWordZ = aPtr[index]>>dist; - while ( index != lastIndex ) { - wordA = aPtr[index + wordIncr]; - zPtr[index] = wordA<<(uNegDist & 31) | partWordZ; - index += wordIncr; - partWordZ = wordA>>dist; - } - zPtr[index] = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub128.c b/deps/SoftFloat-3e/source/s_sub128.c deleted file mode 100644 index 9bf346391010..000000000000 --- a/deps/SoftFloat-3e/source/s_sub128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub128 - -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - - z.v0 = a0 - b0; - z.v64 = a64 - b64 - (a0 < b0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub1XM.c b/deps/SoftFloat-3e/source/s_sub1XM.c deleted file mode 100644 index 30c5d36eea7b..000000000000 --- a/deps/SoftFloat-3e/source/s_sub1XM.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub1XM - -void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = zPtr[index]; - zPtr[index] = wordA - 1; - if ( wordA || (index == lastIndex) ) break; - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub256M.c b/deps/SoftFloat-3e/source/s_sub256M.c deleted file mode 100644 index a4af5a1c9524..000000000000 --- a/deps/SoftFloat-3e/source/s_sub256M.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub256M - -void - softfloat_sub256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) -{ - unsigned int index; - uint_fast8_t borrow; - uint64_t wordA, wordB; - - index = indexWordLo( 4 ); - borrow = 0; - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - zPtr[index] = wordA - wordB - borrow; - if ( index == indexWordHi( 4 ) ) break; - borrow = borrow ? (wordA <= wordB) : (wordA < wordB); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_subM.c b/deps/SoftFloat-3e/source/s_subM.c deleted file mode 100644 index fcccc744cfac..000000000000 --- a/deps/SoftFloat-3e/source/s_subM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_subM - -void - softfloat_subM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint_fast8_t borrow; - uint32_t wordA, wordB; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - borrow = 0; - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - zPtr[index] = wordA - wordB - borrow; - if ( index == lastIndex ) break; - borrow = borrow ? (wordA <= wordB) : (wordA < wordB); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_subMagsExtF80.c b/deps/SoftFloat-3e/source/s_subMagsExtF80.c deleted file mode 100644 index 0c46c61a2b9c..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsExtF80.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - softfloat_subMagsExtF80( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - uint_fast64_t sigA; - int_fast32_t expB; - uint_fast64_t sigB; - int_fast32_t expDiff; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - int_fast32_t expZ; - uint_fast64_t sigExtra; - struct uint128 sig128, uiZ; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( 0 < expDiff ) goto expABigger; - if ( expDiff < 0 ) goto expBBigger; - if ( expA == 0x7FFF ) { - if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - goto propagateNaN; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA; - if ( ! expZ ) expZ = 1; - sigExtra = 0; - if ( sigB < sigA ) goto aBigger; - if ( sigA < sigB ) goto bBigger; - uiZ64 = - packToExtF80UI64( (softfloat_roundingMode == softfloat_round_min), 0 ); - uiZ0 = 0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expBBigger: - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = packToExtF80UI64( signZ ^ 1, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - if ( ! expA ) { - ++expDiff; - sigExtra = 0; - if ( ! expDiff ) goto newlyAlignedBBigger; - } - sig128 = softfloat_shiftRightJam128( sigA, 0, -expDiff ); - sigA = sig128.v64; - sigExtra = sig128.v0; - newlyAlignedBBigger: - expZ = expB; - bBigger: - signZ = ! signZ; - sig128 = softfloat_sub128( sigB, 0, sigA, sigExtra ); - goto normRoundPack; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expABigger: - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - if ( ! expB ) { - --expDiff; - sigExtra = 0; - if ( ! expDiff ) goto newlyAlignedABigger; - } - sig128 = softfloat_shiftRightJam128( sigB, 0, expDiff ); - sigB = sig128.v64; - sigExtra = sig128.v0; - newlyAlignedABigger: - expZ = expA; - aBigger: - sig128 = softfloat_sub128( sigA, 0, sigB, sigExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - normRoundPack: - return - softfloat_normRoundPackToExtF80( - signZ, expZ, sig128.v64, sig128.v0, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF128.c b/deps/SoftFloat-3e/source/s_subMagsF128.c deleted file mode 100644 index e93543f096f9..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF128.c +++ /dev/null @@ -1,139 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - softfloat_subMagsF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - struct uint128 sigA; - int_fast32_t expB; - struct uint128 sigB, sigZ; - int_fast32_t expDiff, expZ; - struct uint128 uiZ; - union ui128_f128 uZ; - - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 4 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 4 ); - expDiff = expA - expB; - if ( 0 < expDiff ) goto expABigger; - if ( expDiff < 0 ) goto expBBigger; - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - } - expZ = expA; - if ( ! expZ ) expZ = 1; - if ( sigB.v64 < sigA.v64 ) goto aBigger; - if ( sigA.v64 < sigB.v64 ) goto bBigger; - if ( sigB.v0 < sigA.v0 ) goto aBigger; - if ( sigA.v0 < sigB.v0 ) goto bBigger; - uiZ.v64 = - packToF128UI64( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - expBBigger: - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = packToF128UI64( signZ ^ 1, 0x7FFF, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - if ( expA ) { - sigA.v64 |= UINT64_C( 0x0010000000000000 ); - } else { - ++expDiff; - if ( ! expDiff ) goto newlyAlignedBBigger; - } - sigA = softfloat_shiftRightJam128( sigA.v64, sigA.v0, -expDiff ); - newlyAlignedBBigger: - expZ = expB; - sigB.v64 |= UINT64_C( 0x0010000000000000 ); - bBigger: - signZ = ! signZ; - sigZ = softfloat_sub128( sigB.v64, sigB.v0, sigA.v64, sigA.v0 ); - goto normRoundPack; - expABigger: - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - if ( expB ) { - sigB.v64 |= UINT64_C( 0x0010000000000000 ); - } else { - --expDiff; - if ( ! expDiff ) goto newlyAlignedABigger; - } - sigB = softfloat_shiftRightJam128( sigB.v64, sigB.v0, expDiff ); - newlyAlignedABigger: - expZ = expA; - sigA.v64 |= UINT64_C( 0x0010000000000000 ); - aBigger: - sigZ = softfloat_sub128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); - normRoundPack: - return softfloat_normRoundPackToF128( signZ, expZ - 5, sigZ.v64, sigZ.v0 ); - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF16.c b/deps/SoftFloat-3e/source/s_subMagsF16.c deleted file mode 100644 index ae1417ea9441..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF16.c +++ /dev/null @@ -1,187 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t softfloat_subMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - int_fast8_t expA; - uint_fast16_t sigA; - int_fast8_t expB; - uint_fast16_t sigB; - int_fast8_t expDiff; - uint_fast16_t uiZ; - int_fast16_t sigDiff; - bool signZ; - int_fast8_t shiftDist, expZ; - uint_fast16_t sigZ, sigX, sigY; - uint_fast32_t sig32Z; - int_fast8_t roundingMode; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF16UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - signZ = signF16UI( uiA ); - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros16( sigDiff ) - 5; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - sigZ = sigDiff<>16; - if ( sig32Z & 0xFFFF ) { - sigZ |= 1; - } else { - if ( ! (sigZ & 0xF) && ((unsigned int) expZ < 0x1E) ) { - sigZ >>= 4; - goto pack; - } - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - subEpsilon: - roundingMode = softfloat_roundingMode; - if ( roundingMode != softfloat_round_near_even ) { - if ( - (roundingMode == softfloat_round_minMag) - || (roundingMode - == (signF16UI( uiZ ) ? softfloat_round_max - : softfloat_round_min)) - ) { - --uiZ; - } -#ifdef SOFTFLOAT_ROUND_ODD - else if ( roundingMode == softfloat_round_odd ) { - uiZ = (uiZ - 1) | 1; - } -#endif - } - softfloat_exceptionFlags |= softfloat_flag_inexact; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - pack: - uiZ = packToF16UI( signZ, expZ, sigZ ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF32.c b/deps/SoftFloat-3e/source/s_subMagsF32.c deleted file mode 100644 index 0c1f32ed6f89..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF32.c +++ /dev/null @@ -1,143 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t softfloat_subMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - int_fast16_t expA; - uint_fast32_t sigA; - int_fast16_t expB; - uint_fast32_t sigB; - int_fast16_t expDiff; - uint_fast32_t uiZ; - int_fast32_t sigDiff; - bool signZ; - int_fast8_t shiftDist; - int_fast16_t expZ; - uint_fast32_t sigX, sigY; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF32UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - signZ = signF32UI( uiA ); - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros32( sigDiff ) - 8; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - uiZ = packToF32UI( signZ, expZ, sigDiff< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t - softfloat_subMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) -{ - int_fast16_t expA; - uint_fast64_t sigA; - int_fast16_t expB; - uint_fast64_t sigB; - int_fast16_t expDiff; - uint_fast64_t uiZ; - int_fast64_t sigDiff; - int_fast8_t shiftDist; - int_fast16_t expZ; - uint_fast64_t sigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros64( sigDiff ) - 11; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - uiZ = packToF64UI( signZ, expZ, sigDiff< -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -bool - softfloat_tryPropagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - uint_fast16_t ui64; - uint64_t ui0; - - ui64 = aSPtr->signExp; - ui0 = aSPtr->signif; - if ( isNaNExtF80UI( ui64, ui0 ) ) goto propagateNaN; - ui64 = bSPtr->signExp; - ui0 = bSPtr->signif; - if ( isNaNExtF80UI( ui64, ui0 ) ) goto propagateNaN; - return false; - propagateNaN: - softfloat_propagateNaNExtF80M( aSPtr, bSPtr, zSPtr ); - return true; - -} - diff --git a/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c b/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c deleted file mode 100644 index bab04a7c0859..000000000000 --- a/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -bool - softfloat_tryPropagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_propagateNaNF128M( aWPtr, bWPtr, zWPtr ); - return true; - } - return false; - -} - diff --git a/deps/SoftFloat-3e/source/softfloat_state.c b/deps/SoftFloat-3e/source/softfloat_state.c deleted file mode 100644 index 0f296654fd48..000000000000 --- a/deps/SoftFloat-3e/source/softfloat_state.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifndef THREAD_LOCAL -#define THREAD_LOCAL -#endif - -THREAD_LOCAL uint_fast8_t softfloat_roundingMode = softfloat_round_near_even; -THREAD_LOCAL uint_fast8_t softfloat_detectTininess = init_detectTininess; -THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags = 0; - -THREAD_LOCAL uint_fast8_t extF80_roundingPrecision = 80; - diff --git a/deps/SoftFloat-3e/source/ui32_to_extF80.c b/deps/SoftFloat-3e/source/ui32_to_extF80.c deleted file mode 100644 index 34f79368f2fe..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_extF80.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t ui32_to_extF80( uint32_t a ) -{ - uint_fast16_t uiZ64; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ); - uiZ64 = 0x401E - shiftDist; - a <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = (uint_fast64_t) a<<32; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui32_to_extF80M.c b/deps/SoftFloat-3e/source/ui32_to_extF80M.c deleted file mode 100644 index 0a0c098c0051..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_extF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = ui32_to_extF80( a ); - -} - -#else - -void ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ); - uiZ64 = packToExtF80UI64( 0, 0x401E - shiftDist ); - sigZ = (uint64_t) (a<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui32_to_f128.c b/deps/SoftFloat-3e/source/ui32_to_f128.c deleted file mode 100644 index c3ab53daf7ce..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f128.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t ui32_to_f128( uint32_t a ) -{ - uint_fast64_t uiZ64; - int_fast8_t shiftDist; - union ui128_f128 uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ) + 17; - uiZ64 = - packToF128UI64( - 0, 0x402E - shiftDist, (uint_fast64_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui32_to_f128M( uint32_t a, float128_t *zPtr ) -{ - - *zPtr = ui32_to_f128( a ); - -} - -#else - -void ui32_to_f128M( uint32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr, uiZ96, uiZ64; - int_fast8_t shiftDist; - uint64_t normA; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ) + 17; - normA = (uint64_t) a<>32 ); - uiZ64 = normA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui32_to_f16.c b/deps/SoftFloat-3e/source/ui32_to_f16.c deleted file mode 100644 index 6fc377bca14c..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f16.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t ui32_to_f16( uint32_t a ) -{ - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - shiftDist = softfloat_countLeadingZeros32( a ) - 21; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - 0, 0x18 - shiftDist, (uint_fast16_t) a<>(-shiftDist) | ((uint32_t) (a<<(shiftDist & 31)) != 0) - : (uint_fast16_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t ui32_to_f32( uint32_t a ) -{ - union ui32_f32 uZ; - - if ( ! a ) { - uZ.ui = 0; - return uZ.f; - } - if ( a & 0x80000000 ) { - return softfloat_roundPackToF32( 0, 0x9D, a>>1 | (a & 1) ); - } else { - return softfloat_normRoundPackToF32( 0, 0x9C, a ); - } - -} - diff --git a/deps/SoftFloat-3e/source/ui32_to_f64.c b/deps/SoftFloat-3e/source/ui32_to_f64.c deleted file mode 100644 index 504f96e6e2b4..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f64.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t ui32_to_f64( uint32_t a ) -{ - uint_fast64_t uiZ; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - if ( ! a ) { - uiZ = 0; - } else { - shiftDist = softfloat_countLeadingZeros32( a ) + 21; - uiZ = - packToF64UI( 0, 0x432 - shiftDist, (uint_fast64_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t ui64_to_extF80( uint64_t a ) -{ - uint_fast16_t uiZ64; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ); - uiZ64 = 0x403E - shiftDist; - a <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = a; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui64_to_extF80M.c b/deps/SoftFloat-3e/source/ui64_to_extF80M.c deleted file mode 100644 index e676d904a4a0..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_extF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = ui64_to_extF80( a ); - -} - -#else - -void ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ); - uiZ64 = packToExtF80UI64( 0, 0x403E - shiftDist ); - sigZ = a<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui64_to_f128.c b/deps/SoftFloat-3e/source/ui64_to_f128.c deleted file mode 100644 index 6ff6a6fcfa57..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f128.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t ui64_to_f128( uint64_t a ) -{ - uint_fast64_t uiZ64, uiZ0; - int_fast8_t shiftDist; - struct uint128 zSig; - union ui128_f128 uZ; - - if ( ! a ) { - uiZ64 = 0; - uiZ0 = 0; - } else { - shiftDist = softfloat_countLeadingZeros64( a ) + 49; - if ( 64 <= shiftDist ) { - zSig.v64 = a<<(shiftDist - 64); - zSig.v0 = 0; - } else { - zSig = softfloat_shortShiftLeft128( 0, a, shiftDist ); - } - uiZ64 = packToF128UI64( 0, 0x406E - shiftDist, zSig.v64 ); - uiZ0 = zSig.v0; - } - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui64_to_f128M.c b/deps/SoftFloat-3e/source/ui64_to_f128M.c deleted file mode 100644 index 043406cc4f83..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f128M.c +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui64_to_f128M( uint64_t a, float128_t *zPtr ) -{ - - *zPtr = ui64_to_f128( a ); - -} - -#else - -void ui64_to_f128M( uint64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr, uiZ96, uiZ64; - uint_fast8_t shiftDist; - uint32_t *ptr; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ) + 17; - if ( shiftDist < 32 ) { - ptr = zWPtr + indexMultiwordHi( 4, 3 ); - ptr[indexWord( 3, 2 )] = 0; - ptr[indexWord( 3, 1 )] = a>>32; - ptr[indexWord( 3, 0 )] = a; - softfloat_shortShiftLeft96M( ptr, shiftDist, ptr ); - ptr[indexWordHi( 3 )] = - packToF128UI96( 0, 0x404E - shiftDist, ptr[indexWordHi( 3 )] ); - return; - } - a <<= shiftDist - 32; - uiZ96 = packToF128UI96( 0, 0x404E - shiftDist, a>>32 ); - uiZ64 = a; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui64_to_f16.c b/deps/SoftFloat-3e/source/ui64_to_f16.c deleted file mode 100644 index 3d58e85cf647..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f16.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t ui64_to_f16( uint64_t a ) -{ - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - shiftDist = softfloat_countLeadingZeros64( a ) - 53; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - 0, 0x18 - shiftDist, (uint_fast16_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t ui64_to_f32( uint64_t a ) -{ - int_fast8_t shiftDist; - union ui32_f32 u; - uint_fast32_t sig; - - shiftDist = softfloat_countLeadingZeros64( a ) - 40; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF32UI( - 0, 0x95 - shiftDist, (uint_fast32_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t ui64_to_f64( uint64_t a ) -{ - union ui64_f64 uZ; - - if ( ! a ) { - uZ.ui = 0; - return uZ.f; - } - if ( a & UINT64_C( 0x8000000000000000 ) ) { - return - softfloat_roundPackToF64( - 0, 0x43D, softfloat_shortShiftRightJam64( a, 1 ) ); - } else { - return softfloat_normRoundPackToF64( 0, 0x43C, a ); - } - -} - diff --git a/src/Compilation.zig b/src/Compilation.zig index 853d83485a77..e3c45678e2b1 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -30,7 +30,6 @@ const fatal = @import("main.zig").fatal; const clangMain = @import("main.zig").clangMain; const Module = @import("Module.zig"); const Cache = @import("Cache.zig"); -const stage1 = @import("stage1.zig"); const translate_c = @import("translate_c.zig"); const c_codegen = @import("codegen/c.zig"); const ThreadPool = @import("ThreadPool.zig"); @@ -5411,199 +5410,6 @@ fn buildOutputFromZig( }; } -fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node) !void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - // Here we use the legacy stage1 C++ compiler to compile Zig code. - const mod = comp.bin_file.options.module.?; - const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type. - const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ - mod.main_pkg.root_src_path, - }); - const zig_lib_dir = comp.zig_lib_directory.path.?; - const target = comp.getTarget(); - - // The include_compiler_rt stored in the bin file options here means that we need - // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend - // we need to tell stage1 to include compiler-rt only if stage1 is the place that - // needs to provide those symbols. Otherwise the stage2 infrastructure will take care - // of it in the linker, by putting compiler_rt.o into a static archive, or linking - // compiler_rt.a against an executable. In other words we only want to set this flag - // for stage1 if we are using build-obj. - const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and - comp.bin_file.options.include_compiler_rt; - - const stage2_target = try arena.create(stage1.Stage2Target); - stage2_target.* = .{ - .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch - .os = @enumToInt(target.os.tag), - .abi = @enumToInt(target.abi), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_cpu = false, // Only true when bootstrapping the compiler. - .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null, - .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?, - .llvm_target_abi = if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, - }; - - const main_pkg_path = mod.main_pkg.root_src_directory.path orelse ""; - const builtin_pkg = mod.main_pkg.table.get("builtin").?; - const builtin_zig_path = try builtin_pkg.root_src_directory.join(arena, &.{builtin_pkg.root_src_path}); - - const stage1_module = stage1.create( - @enumToInt(comp.bin_file.options.optimize_mode), - main_pkg_path.ptr, - main_pkg_path.len, - main_zig_file.ptr, - main_zig_file.len, - zig_lib_dir.ptr, - zig_lib_dir.len, - stage2_target, - comp.bin_file.options.is_test, - ) orelse return error.OutOfMemory; - - const emit_bin_path = if (comp.bin_file.options.emit != null) blk: { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = comp.bin_file.options.root_name, - .target = target, - .output_mode = .Obj, - }); - break :blk try directory.join(arena, &[_][]const u8{obj_basename}); - } else ""; - - if (mod.emit_h != null) { - log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); - } - const emit_h_loc: ?EmitLoc = if (mod.emit_h) |emit_h| emit_h.loc else null; - const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory); - const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); - const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); - const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory); - const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null); - const test_filter = comp.test_filter orelse ""[0..0]; - const test_name_prefix = comp.test_name_prefix orelse ""[0..0]; - const subsystem = if (comp.bin_file.options.subsystem) |s| - @intToEnum(stage1.TargetSubsystem, @enumToInt(s)) - else - stage1.TargetSubsystem.Auto; - stage1_module.* = .{ - .root_name_ptr = comp.bin_file.options.root_name.ptr, - .root_name_len = comp.bin_file.options.root_name.len, - .emit_o_ptr = emit_bin_path.ptr, - .emit_o_len = emit_bin_path.len, - .emit_h_ptr = emit_h_path.ptr, - .emit_h_len = emit_h_path.len, - .emit_asm_ptr = emit_asm_path.ptr, - .emit_asm_len = emit_asm_path.len, - .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr, - .emit_llvm_ir_len = emit_llvm_ir_path.len, - .emit_bitcode_ptr = emit_llvm_bc_path.ptr, - .emit_bitcode_len = emit_llvm_bc_path.len, - .builtin_zig_path_ptr = builtin_zig_path.ptr, - .builtin_zig_path_len = builtin_zig_path.len, - .test_filter_ptr = test_filter.ptr, - .test_filter_len = test_filter.len, - .test_name_prefix_ptr = test_name_prefix.ptr, - .test_name_prefix_len = test_name_prefix.len, - .userdata = @ptrToInt(comp), - .main_pkg = stage1_pkg, - .code_model = @enumToInt(comp.bin_file.options.machine_code_model), - .subsystem = subsystem, - .err_color = @enumToInt(comp.color), - .pic = comp.bin_file.options.pic, - .pie = comp.bin_file.options.pie, - .lto = comp.bin_file.options.lto, - .unwind_tables = comp.unwind_tables, - .link_libc = comp.bin_file.options.link_libc, - .link_libcpp = comp.bin_file.options.link_libcpp, - .strip = comp.bin_file.options.strip, - .is_single_threaded = comp.bin_file.options.single_threaded, - .dll_export_fns = comp.bin_file.options.dll_export_fns, - .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, - .valgrind_enabled = comp.bin_file.options.valgrind, - .tsan_enabled = comp.bin_file.options.tsan, - .function_sections = comp.bin_file.options.function_sections, - .include_compiler_rt = include_compiler_rt, - .enable_stack_probing = comp.bin_file.options.stack_check, - .red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .enable_time_report = comp.time_report, - .enable_stack_report = comp.stack_report, - .test_is_evented = comp.test_evented_io, - .verbose_ir = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .main_progress_node = main_progress_node, - .have_c_main = false, - .have_winmain = false, - .have_wwinmain = false, - .have_winmain_crt_startup = false, - .have_wwinmain_crt_startup = false, - .have_dllmain_crt_startup = false, - }; - - stage1_module.build_object(); - - mod.stage1_flags = .{ - .have_c_main = stage1_module.have_c_main, - .have_winmain = stage1_module.have_winmain, - .have_wwinmain = stage1_module.have_wwinmain, - .have_winmain_crt_startup = stage1_module.have_winmain_crt_startup, - .have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup, - .have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup, - }; - - stage1_module.destroy(); -} - -fn stage1LocPath(arena: Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 { - const loc = opt_loc orelse return ""; - const directory = loc.directory orelse cache_directory; - return directory.join(arena, &[_][]const u8{loc.basename}); -} - -fn createStage1Pkg( - arena: Allocator, - name: []const u8, - pkg: *Package, - parent_pkg: ?*stage1.Pkg, -) error{OutOfMemory}!*stage1.Pkg { - const child_pkg = try arena.create(stage1.Pkg); - - const pkg_children = blk: { - var children = std.ArrayList(*stage1.Pkg).init(arena); - var it = pkg.table.iterator(); - while (it.next()) |entry| { - if (mem.eql(u8, entry.key_ptr.*, "std") or - mem.eql(u8, entry.key_ptr.*, "builtin") or - mem.eql(u8, entry.key_ptr.*, "root")) - { - continue; - } - try children.append(try createStage1Pkg(arena, entry.key_ptr.*, entry.value_ptr.*, child_pkg)); - } - break :blk children.items; - }; - - const src_path = try pkg.root_src_directory.join(arena, &[_][]const u8{pkg.root_src_path}); - - child_pkg.* = .{ - .name_ptr = name.ptr, - .name_len = name.len, - .path_ptr = src_path.ptr, - .path_len = src_path.len, - .children_ptr = pkg_children.ptr, - .children_len = pkg_children.len, - .parent = parent_pkg, - }; - return child_pkg; -} - pub fn build_crt_file( comp: *Compilation, root_name: []const u8, diff --git a/src/stage1.zig b/src/stage1.zig deleted file mode 100644 index bb2752c80296..000000000000 --- a/src/stage1.zig +++ /dev/null @@ -1,479 +0,0 @@ -//! This is the main entry point for the Zig/C++ hybrid compiler (stage1). -//! It has the functions exported from Zig, called in C++, and bindings for -//! the functions exported from C++, called from Zig. - -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; -const CrossTarget = std.zig.CrossTarget; -const Target = std.Target; -const builtin = @import("builtin"); - -const build_options = @import("build_options"); -const stage2 = @import("main.zig"); -const fatal = stage2.fatal; -const Compilation = @import("Compilation.zig"); -const translate_c = @import("translate_c.zig"); -const target_util = @import("target.zig"); - -comptime { - assert(builtin.link_libc); - assert(build_options.have_stage1); - assert(build_options.have_llvm); - if (!builtin.is_test) { - @export(main, .{ .name = "main" }); - } -} - -pub const log = stage2.log; -pub const log_level = stage2.log_level; - -pub fn main(argc: c_int, argv: [*][*:0]u8) callconv(.C) c_int { - std.os.argv = argv[0..@intCast(usize, argc)]; - - std.debug.maybeEnableSegfaultHandler(); - - zig_stage1_os_init(); - - const gpa = std.heap.c_allocator; - var arena_instance = std.heap.ArenaAllocator.init(gpa); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - - const args: []const []const u8 = args: { - if (builtin.os.tag == .windows) { - break :args std.process.argsAlloc(arena) catch fatal("{s}", .{"OutOfMemory"}); - } else { - const args = arena.alloc([]const u8, @intCast(usize, argc)) catch fatal("{s}", .{"OutOfMemory"}); - for (args) |*arg, i| { - arg.* = mem.sliceTo(argv[i], 0); - } - break :args args; - } - }; - - if (builtin.mode == .Debug) { - stage2.mainArgs(gpa, arena, args) catch unreachable; - } else { - stage2.mainArgs(gpa, arena, args) catch |err| fatal("{s}", .{@errorName(err)}); - } - return 0; -} - -/// Matches stage2.Color; -pub const ErrColor = c_int; -/// Matches std.builtin.CodeModel -pub const CodeModel = c_int; -/// Matches std.Target.Os.Tag -pub const OS = c_int; -/// Matches std.builtin.BuildMode -pub const BuildMode = c_int; - -pub const TargetSubsystem = enum(c_int) { - Console, - Windows, - Posix, - Native, - EfiApplication, - EfiBootServiceDriver, - EfiRom, - EfiRuntimeDriver, - Auto, -}; - -pub const Pkg = extern struct { - name_ptr: [*]const u8, - name_len: usize, - path_ptr: [*]const u8, - path_len: usize, - children_ptr: [*]*Pkg, - children_len: usize, - parent: ?*Pkg, -}; - -pub const Module = extern struct { - root_name_ptr: [*]const u8, - root_name_len: usize, - emit_o_ptr: [*]const u8, - emit_o_len: usize, - emit_h_ptr: [*]const u8, - emit_h_len: usize, - emit_asm_ptr: [*]const u8, - emit_asm_len: usize, - emit_llvm_ir_ptr: [*]const u8, - emit_llvm_ir_len: usize, - emit_bitcode_ptr: [*]const u8, - emit_bitcode_len: usize, - builtin_zig_path_ptr: [*]const u8, - builtin_zig_path_len: usize, - test_filter_ptr: [*]const u8, - test_filter_len: usize, - test_name_prefix_ptr: [*]const u8, - test_name_prefix_len: usize, - userdata: usize, - main_pkg: *Pkg, - main_progress_node: ?*std.Progress.Node, - code_model: CodeModel, - subsystem: TargetSubsystem, - err_color: ErrColor, - pic: bool, - pie: bool, - lto: bool, - unwind_tables: bool, - link_libc: bool, - link_libcpp: bool, - strip: bool, - is_single_threaded: bool, - dll_export_fns: bool, - link_mode_dynamic: bool, - valgrind_enabled: bool, - tsan_enabled: bool, - function_sections: bool, - include_compiler_rt: bool, - enable_stack_probing: bool, - red_zone: bool, - omit_frame_pointer: bool, - enable_time_report: bool, - enable_stack_report: bool, - test_is_evented: bool, - verbose_ir: bool, - verbose_llvm_ir: bool, - verbose_cimport: bool, - verbose_llvm_cpu_features: bool, - - // Set by stage1 - have_c_main: bool, - have_winmain: bool, - have_wwinmain: bool, - have_winmain_crt_startup: bool, - have_wwinmain_crt_startup: bool, - have_dllmain_crt_startup: bool, - - pub fn build_object(mod: *Module) void { - zig_stage1_build_object(mod); - } - - pub fn destroy(mod: *Module) void { - zig_stage1_destroy(mod); - } -}; - -pub const os_init = zig_stage1_os_init; -extern fn zig_stage1_os_init() void; - -pub const create = zig_stage1_create; -extern fn zig_stage1_create( - optimize_mode: BuildMode, - main_pkg_path_ptr: [*]const u8, - main_pkg_path_len: usize, - root_src_path_ptr: [*]const u8, - root_src_path_len: usize, - zig_lib_dir_ptr: [*c]const u8, - zig_lib_dir_len: usize, - target: [*c]const Stage2Target, - is_test_build: bool, -) ?*Module; - -extern fn zig_stage1_build_object(*Module) void; -extern fn zig_stage1_destroy(*Module) void; - -// ABI warning -export fn stage2_panic(ptr: [*]const u8, len: usize) void { - @panic(ptr[0..len]); -} - -// ABI warning -const Error = enum(c_int) { - None, - OutOfMemory, - InvalidFormat, - SemanticAnalyzeFail, - AccessDenied, - Interrupted, - SystemResources, - FileNotFound, - FileSystem, - FileTooBig, - DivByZero, - Overflow, - PathAlreadyExists, - Unexpected, - ExactDivRemainder, - NegativeDenominator, - ShiftedOutOneBits, - CCompileErrors, - EndOfFile, - IsDir, - NotDir, - UnsupportedOperatingSystem, - SharingViolation, - PipeBusy, - PrimitiveTypeNotFound, - CacheUnavailable, - PathTooLong, - CCompilerCannotFindFile, - NoCCompilerInstalled, - ReadingDepFile, - InvalidDepFile, - MissingArchitecture, - MissingOperatingSystem, - UnknownArchitecture, - UnknownOperatingSystem, - UnknownABI, - InvalidFilename, - DiskQuota, - DiskSpace, - UnexpectedWriteFailure, - UnexpectedSeekFailure, - UnexpectedFileTruncationFailure, - Unimplemented, - OperationAborted, - BrokenPipe, - NoSpaceLeft, - NotLazy, - IsAsync, - ImportOutsidePkgPath, - UnknownCpuModel, - UnknownCpuFeature, - InvalidCpuFeatures, - InvalidLlvmCpuFeaturesFormat, - UnknownApplicationBinaryInterface, - ASTUnitFailure, - BadPathName, - SymLinkLoop, - ProcessFdQuotaExceeded, - SystemFdQuotaExceeded, - NoDevice, - DeviceBusy, - UnableToSpawnCCompiler, - CCompilerExitCode, - CCompilerCrashed, - CCompilerCannotFindHeaders, - LibCRuntimeNotFound, - LibCStdLibHeaderNotFound, - LibCKernel32LibNotFound, - UnsupportedArchitecture, - WindowsSdkNotFound, - UnknownDynamicLinkerPath, - TargetHasNoDynamicLinker, - InvalidAbiVersion, - InvalidOperatingSystemVersion, - UnknownClangOption, - NestedResponseFile, - ZigIsTheCCompiler, - FileBusy, - Locked, - InvalidCharacter, - UnicodePointTooLarge, -}; - -// ABI warning -export fn stage2_version_string() [*:0]const u8 { - return build_options.version; -} - -// ABI warning -export fn stage2_version() Stage2SemVer { - return .{ - .major = build_options.semver.major, - .minor = build_options.semver.minor, - .patch = build_options.semver.patch, - }; -} - -// ABI warning -export fn stage2_attach_segfault_handler() void { - if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) { - std.debug.attachSegfaultHandler(); - } -} - -// ABI warning -export fn stage2_progress_create() *std.Progress { - const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory"); - // If the terminal is dumb, we dont want to show the user all the - // output. - ptr.* = std.Progress{ .dont_print_on_dumb = true }; - return ptr; -} - -// ABI warning -export fn stage2_progress_destroy(progress: *std.Progress) void { - std.heap.c_allocator.destroy(progress); -} - -// ABI warning -export fn stage2_progress_start_root( - progress: *std.Progress, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - return progress.start(name_ptr[0..name_len], estimated_total_items); -} - -// ABI warning -export fn stage2_progress_disable_tty(progress: *std.Progress) void { - progress.terminal = null; -} - -// ABI warning -export fn stage2_progress_start( - node: *std.Progress.Node, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory"); - child_node.* = node.start( - name_ptr[0..name_len], - estimated_total_items, - ); - child_node.activate(); - return child_node; -} - -// ABI warning -export fn stage2_progress_end(node: *std.Progress.Node) void { - node.end(); - if (&node.context.root != node) { - std.heap.c_allocator.destroy(node); - } -} - -// ABI warning -export fn stage2_progress_complete_one(node: *std.Progress.Node) void { - node.completeOne(); -} - -// ABI warning -export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void { - node.setCompletedItems(done_count); - node.setEstimatedTotalItems(total_count); - node.activate(); - node.context.maybeRefresh(); -} - -// ABI warning -pub const Stage2Target = extern struct { - arch: c_int, - os: OS, - abi: c_int, - - is_native_os: bool, - is_native_cpu: bool, - - llvm_cpu_name: ?[*:0]const u8, - llvm_cpu_features: ?[*:0]const u8, - llvm_target_abi: ?[*:0]const u8, -}; - -// ABI warning -const Stage2SemVer = extern struct { - major: u32, - minor: u32, - patch: u32, -}; - -// ABI warning -export fn stage2_cimport( - stage1: *Module, - c_src_ptr: [*]const u8, - c_src_len: usize, - out_zig_path_ptr: *[*]const u8, - out_zig_path_len: *usize, - out_errors_ptr: *[*]translate_c.ClangErrMsg, - out_errors_len: *usize, -) Error { - const comp = @intToPtr(*Compilation, stage1.userdata); - const c_src = c_src_ptr[0..c_src_len]; - const result = comp.cImport(c_src) catch |err| switch (err) { - error.SystemResources => return .SystemResources, - error.OperationAborted => return .OperationAborted, - error.BrokenPipe => return .BrokenPipe, - error.DiskQuota => return .DiskQuota, - error.FileTooBig => return .FileTooBig, - error.NoSpaceLeft => return .NoSpaceLeft, - error.AccessDenied => return .AccessDenied, - error.OutOfMemory => return .OutOfMemory, - error.Unexpected => return .Unexpected, - error.InputOutput => return .FileSystem, - error.ASTUnitFailure => return .ASTUnitFailure, - error.CacheUnavailable => return .CacheUnavailable, - else => return .Unexpected, - }; - out_zig_path_ptr.* = result.out_zig_path.ptr; - out_zig_path_len.* = result.out_zig_path.len; - out_errors_ptr.* = result.errors.ptr; - out_errors_len.* = result.errors.len; - if (result.errors.len != 0) return .CCompileErrors; - return Error.None; -} - -export fn stage2_add_link_lib( - stage1: *Module, - lib_name_ptr: [*c]const u8, - lib_name_len: usize, - symbol_name_ptr: [*c]const u8, - symbol_name_len: usize, -) ?[*:0]const u8 { - _ = symbol_name_len; - _ = symbol_name_ptr; - const comp = @intToPtr(*Compilation, stage1.userdata); - const lib_name = lib_name_ptr[0..lib_name_len]; - const target = comp.getTarget(); - const is_libc = target_util.is_libc_lib_name(target, lib_name); - if (is_libc) { - if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { - return "dependency on libc must be explicitly specified in the build command"; - } - return null; - } - if (target_util.is_libcpp_lib_name(target, lib_name)) { - if (!comp.bin_file.options.link_libcpp) { - return "dependency on libc++ must be explicitly specified in the build command"; - } - return null; - } - if (!target.isWasm() and !comp.bin_file.options.pic) { - return std.fmt.allocPrintZ( - comp.gpa, - "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", - .{ lib_name, lib_name }, - ) catch "out of memory"; - } - comp.stage1AddLinkLib(lib_name) catch |err| { - return std.fmt.allocPrintZ(comp.gpa, "unable to add link lib '{s}': {s}", .{ - lib_name, @errorName(err), - }) catch "out of memory"; - }; - return null; -} - -export fn stage2_fetch_file( - stage1: *Module, - path_ptr: [*]const u8, - path_len: usize, - result_len: *usize, -) ?[*]const u8 { - const comp = @intToPtr(*Compilation, stage1.userdata); - const file_path = path_ptr[0..path_len]; - const max_file_size = std.math.maxInt(u32); - const contents = if (comp.whole_cache_manifest) |man| blk: { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - break :blk man.addFilePostFetch(file_path, max_file_size) catch return null; - } else std.fs.cwd().readFileAlloc(comp.gpa, file_path, max_file_size) catch return null; - result_len.* = contents.len; - // TODO https://github.com/ziglang/zig/issues/3328#issuecomment-716749475 - if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1); - return contents.ptr; -} - -export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error { - if (name_len == 0) return Error.None; - const comp = @intToPtr(*Compilation, stage1.userdata); - const sym_name = comp.gpa.dupe(u8, name_ptr[0..name_len]) catch return Error.OutOfMemory; - comp.export_symbol_names.append(comp.gpa, sym_name) catch return Error.OutOfMemory; - return Error.None; -} diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp deleted file mode 100644 index f29110b94bfd..000000000000 --- a/src/stage1/all_types.hpp +++ /dev/null @@ -1,4746 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ALL_TYPES_HPP -#define ZIG_ALL_TYPES_HPP - -#include "list.hpp" -#include "buffer.hpp" -#include "zig_llvm.h" -#include "hash_map.hpp" -#include "errmsg.hpp" -#include "bigint.hpp" -#include "bigfloat.hpp" -#include "target.hpp" -#include "tokenizer.hpp" - -struct AstNode; -struct ZigFn; -struct Scope; -struct ScopeBlock; -struct ScopeFnDef; -struct ScopeExpr; -struct ZigType; -struct ZigVar; -struct ErrorTableEntry; -struct BuiltinFnEntry; -struct TypeStructField; -struct CodeGen; -struct ZigValue; -struct Stage1ZirInst; -struct Stage1AirInst; -struct Stage1AirInstCast; -struct Stage1AirInstAlloca; -struct Stage1AirInstCall; -struct Stage1AirInstAwait; -struct Stage1ZirBasicBlock; -struct Stage1AirBasicBlock; -struct ScopeDecls; -struct ZigWindowsSDK; -struct Tld; -struct TldExport; -struct IrAnalyze; -struct ResultLoc; -struct ResultLocPeer; -struct ResultLocPeerParent; -struct ResultLocBitCast; -struct ResultLocCast; -struct ResultLocReturn; -struct Stage1Air; - -enum FileExt { - FileExtUnknown, - FileExtAsm, - FileExtC, - FileExtCpp, - FileExtHeader, - FileExtLLVMIr, - FileExtLLVMBitCode, -}; - -enum PtrLen { - PtrLenUnknown, - PtrLenSingle, - PtrLenC, -}; - -enum CallingConvention { - CallingConventionUnspecified, - CallingConventionC, - CallingConventionNaked, - CallingConventionAsync, - CallingConventionInline, - CallingConventionInterrupt, - CallingConventionSignal, - CallingConventionStdcall, - CallingConventionFastcall, - CallingConventionVectorcall, - CallingConventionThiscall, - CallingConventionAPCS, - CallingConventionAAPCS, - CallingConventionAAPCSVFP, - CallingConventionSysV, - CallingConventionWin64, - CallingConventionPtxKernel, - CallingConventionAmdgpuKernel -}; - -// Stage 1 supports only the generic address space -enum AddressSpace { - AddressSpaceGeneric, - AddressSpaceGS, - AddressSpaceFS, - AddressSpaceSS, - AddressSpaceGlobal, - AddressSpaceConstant, - AddressSpaceParam, - AddressSpaceShared, - AddressSpaceLocal, -}; - -// This one corresponds to the builtin.zig enum. -enum BuiltinPtrSize { - BuiltinPtrSizeOne, - BuiltinPtrSizeMany, - BuiltinPtrSizeSlice, - BuiltinPtrSizeC, -}; - -enum UndefAllowed { - UndefOk, - UndefBad, - LazyOkNoUndef, - LazyOk, -}; - -enum X64CABIClass { - X64CABIClass_Unknown, - X64CABIClass_MEMORY, - X64CABIClass_MEMORY_nobyval, - X64CABIClass_INTEGER, - X64CABIClass_SSE, - X64CABIClass_AGG, -}; - -struct Stage1Zir { - ZigList basic_block_list; - Buf *name; - ZigFn *name_fn; - Scope *begin_scope; - ErrorMsg *first_err_trace_msg; - ZigList tld_list; - - bool is_inline; - bool need_err_code_spill; -}; - -struct Stage1Air { - ZigList basic_block_list; - Buf *name; - ZigFn *name_fn; - size_t mem_slot_count; - size_t next_debug_id; - Buf *c_import_buf; - AstNode *source_node; - Stage1Air *parent_exec; - Stage1Zir *source_exec; - Scope *begin_scope; - ErrorMsg *first_err_trace_msg; - ZigList tld_list; - - bool is_inline; - bool need_err_code_spill; - - // This is a function for use in the debugger to print - // the source location. - void src(); -}; - -enum OutType { - OutTypeUnknown, - OutTypeExe, - OutTypeLib, - OutTypeObj, -}; - -enum ConstParentId { - ConstParentIdNone, - ConstParentIdStruct, - ConstParentIdErrUnionCode, - ConstParentIdErrUnionPayload, - ConstParentIdOptionalPayload, - ConstParentIdArray, - ConstParentIdUnion, - ConstParentIdScalar, -}; - -struct ConstParent { - ConstParentId id; - - union { - struct { - ZigValue *array_val; - size_t elem_index; - } p_array; - struct { - ZigValue *struct_val; - size_t field_index; - } p_struct; - struct { - ZigValue *err_union_val; - } p_err_union_code; - struct { - ZigValue *err_union_val; - } p_err_union_payload; - struct { - ZigValue *optional_val; - } p_optional_payload; - struct { - ZigValue *union_val; - } p_union; - struct { - ZigValue *scalar_val; - } p_scalar; - } data; -}; - -struct ConstStructValue { - ZigValue **fields; -}; - -struct ConstUnionValue { - BigInt tag; - ZigValue *payload; -}; - -enum ConstArraySpecial { - ConstArraySpecialNone, - ConstArraySpecialUndef, - ConstArraySpecialBuf, -}; - -struct ConstArrayValue { - ConstArraySpecial special; - union { - struct { - ZigValue *elements; - } s_none; - Buf *s_buf; - } data; -}; - -enum ConstPtrSpecial { - // Enforce explicitly setting this ID by making the zero value invalid. - ConstPtrSpecialInvalid, - // The pointer is a reference to a single object. - ConstPtrSpecialRef, - // The pointer points to an element in an underlying array. - // Not to be confused with ConstPtrSpecialSubArray. - ConstPtrSpecialBaseArray, - // The pointer points to a field in an underlying struct. - ConstPtrSpecialBaseStruct, - // The pointer points to the error set field of an error union - ConstPtrSpecialBaseErrorUnionCode, - // The pointer points to the payload field of an error union - ConstPtrSpecialBaseErrorUnionPayload, - // The pointer points to the payload field of an optional - ConstPtrSpecialBaseOptionalPayload, - // This means that we did a compile-time pointer reinterpret and we cannot - // understand the value of pointee at compile time. However, we will still - // emit a binary with a compile time known address. - // In this case index is the numeric address value. - ConstPtrSpecialHardCodedAddr, - // This means that the pointer represents memory of assigning to _. - // That is, storing discards the data, and loading is invalid. - ConstPtrSpecialDiscard, - // This is actually a function. - ConstPtrSpecialFunction, - // This means the pointer is null. This is only allowed when the type is ?*T. - // We use this instead of ConstPtrSpecialHardCodedAddr because often we check - // for that value to avoid doing comptime work. - // We need the data layout for ConstCastOnly == true - // types to be the same, so all optionals of pointer types use x_ptr - // instead of x_optional. - ConstPtrSpecialNull, - // The pointer points to a sub-array (not an individual element). - // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same - // union payload struct (base_array). - ConstPtrSpecialSubArray, -}; - -enum ConstPtrMut { - // The pointer points to memory that is known at compile time and immutable. - ConstPtrMutComptimeConst, - // This means that the pointer points to memory used by a comptime variable, - // so attempting to write a non-compile-time known value is an error - // But the underlying value is allowed to change at compile time. - ConstPtrMutComptimeVar, - // The pointer points to memory that is known only at runtime. - // For example it may point to the initializer value of a variable. - ConstPtrMutRuntimeVar, - // The pointer points to memory for which it must be inferred whether the - // value is comptime known or not. - ConstPtrMutInfer, -}; - -struct ConstPtrValue { - ConstPtrSpecial special; - ConstPtrMut mut; - - union { - struct { - ZigValue *pointee; - } ref; - struct { - ZigValue *array_val; - size_t elem_index; - } base_array; - struct { - ZigValue *struct_val; - size_t field_index; - } base_struct; - struct { - ZigValue *err_union_val; - } base_err_union_code; - struct { - ZigValue *err_union_val; - } base_err_union_payload; - struct { - ZigValue *optional_val; - } base_optional_payload; - struct { - uint64_t addr; - } hard_coded_addr; - struct { - ZigFn *fn_entry; - } fn; - } data; -}; - -struct ConstErrValue { - ZigValue *error_set; - ZigValue *payload; -}; - -struct ConstBoundFnValue { - ZigFn *fn; - Stage1AirInst *first_arg; - AstNode *first_arg_src; -}; - -struct ConstArgTuple { - size_t start_index; - size_t end_index; -}; - -enum ConstValSpecial { - // The value is only available at runtime. However there may be runtime hints - // narrowing the possible values down via the `data.rh_*` fields. - ConstValSpecialRuntime, - // The value is comptime-known and resolved. The `data.x_*` fields can be - // accessed. - ConstValSpecialStatic, - // The value is comptime-known to be `undefined`. - ConstValSpecialUndef, - // The value is comptime-known, but not yet resolved. The lazy value system - // helps avoid dependency loops by providing answers to certain questions - // about values without forcing them to be resolved. For example, the - // equation `@sizeOf(Foo) == 0` can be resolved without forcing the struct - // layout of `Foo` because we can know whether `Foo` is zero bits without - // performing field layout. - // A `ZigValue` can be converted from Lazy to Static/Undef by calling the - // appropriate resolve function. - ConstValSpecialLazy, -}; - -enum RuntimeHintErrorUnion { - RuntimeHintErrorUnionUnknown, - RuntimeHintErrorUnionError, - RuntimeHintErrorUnionNonError, -}; - -enum RuntimeHintOptional { - RuntimeHintOptionalUnknown, - RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known. - RuntimeHintOptionalNonNull, -}; - -enum RuntimeHintPtr { - RuntimeHintPtrUnknown, - RuntimeHintPtrStack, - RuntimeHintPtrNonStack, -}; - -enum RuntimeHintSliceId { - RuntimeHintSliceIdUnknown, - RuntimeHintSliceIdLen, -}; - -struct RuntimeHintSlice { - enum RuntimeHintSliceId id; - uint64_t len; -}; - -enum LazyValueId { - LazyValueIdInvalid, - LazyValueIdAlignOf, - LazyValueIdSizeOf, - LazyValueIdPtrType, - LazyValueIdPtrTypeSimple, - LazyValueIdPtrTypeSimpleConst, - LazyValueIdOptType, - LazyValueIdSliceType, - LazyValueIdFnType, - LazyValueIdErrUnionType, - LazyValueIdArrayType, - LazyValueIdTypeInfoDecls, -}; - -struct LazyValue { - LazyValueId id; -}; - -struct LazyValueTypeInfoDecls { - LazyValue base; - - IrAnalyze *ira; - - ScopeDecls *decls_scope; - AstNode *source_node; -}; - -struct LazyValueAlignOf { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *target_type; -}; - -struct LazyValueSizeOf { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *target_type; - - bool bit_size; -}; - -struct LazyValueSliceType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - Stage1AirInst *align_inst; // can be null - - bool is_const; - bool is_volatile; - bool is_allowzero; -}; - -struct LazyValueArrayType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - uint64_t length; -}; - -struct LazyValuePtrType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - Stage1AirInst *align_inst; // can be null - - PtrLen ptr_len; - uint32_t bit_offset_in_host; - - uint32_t host_int_bytes; - bool is_const; - bool is_volatile; - bool is_allowzero; -}; - -struct LazyValuePtrTypeSimple { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *elem_type; -}; - -struct LazyValueOptType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *payload_type; -}; - -struct LazyValueFnType { - LazyValue base; - - IrAnalyze *ira; - AstNode *proto_node; - Stage1AirInst **param_types; - Stage1AirInst *align_inst; // can be null - Stage1AirInst *return_type; - - CallingConvention cc; - bool is_generic; -}; - -struct LazyValueErrUnionType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *err_set_type; - Stage1AirInst *payload_type; - Buf *type_name; -}; - -struct ZigValue { - ZigType *type; - // This field determines how the value is stored. It must be checked - // before accessing the `data` union. - ConstValSpecial special; - uint32_t llvm_align; - ConstParent parent; - LLVMValueRef llvm_value; - LLVMValueRef llvm_global; - - union { - // populated if special == ConstValSpecialLazy - LazyValue *x_lazy; - - // populated if special == ConstValSpecialStatic - BigInt x_bigint; - BigFloat x_bigfloat; - float16_t x_f16; - float x_f32; - double x_f64; - extFloat80_t x_f80; - float128_t x_f128; - bool x_bool; - ConstBoundFnValue x_bound_fn; - ZigType *x_type; - ZigValue *x_optional; - ConstErrValue x_err_union; - ErrorTableEntry *x_err_set; - BigInt x_enum_tag; - ConstStructValue x_struct; - ConstUnionValue x_union; - ConstArrayValue x_array; - ConstPtrValue x_ptr; - ConstArgTuple x_arg_tuple; - Buf *x_enum_literal; - - // populated if special == ConstValSpecialRuntime - RuntimeHintErrorUnion rh_error_union; - RuntimeHintOptional rh_maybe; - RuntimeHintPtr rh_ptr; - RuntimeHintSlice rh_slice; - } data; - - // uncomment this to find bugs. can't leave it uncommented because of a gcc-9 warning - //ZigValue& operator= (const ZigValue &other) = delete; // use copy_const_val - - ZigValue(const ZigValue &other) = delete; // plz zero initialize with ZigValue val = {}; - - // for use in debuggers - void dump(); -}; - -enum ReturnKnowledge { - ReturnKnowledgeUnknown, - ReturnKnowledgeKnownError, - ReturnKnowledgeKnownNonError, - ReturnKnowledgeKnownNull, - ReturnKnowledgeKnownNonNull, - ReturnKnowledgeSkipDefers, -}; - -enum VisibMod { - VisibModPrivate, - VisibModPub, -}; - -enum GlobalLinkageId { - GlobalLinkageIdInternal, - GlobalLinkageIdStrong, - GlobalLinkageIdWeak, - GlobalLinkageIdLinkOnce, -}; - -enum TldId { - TldIdVar, - TldIdFn, - TldIdContainer, - TldIdCompTime, - TldIdUsingNamespace, -}; - -enum TldResolution { - TldResolutionUnresolved, - TldResolutionResolving, - TldResolutionInvalid, - TldResolutionOkLazy, - TldResolutionOk, -}; - -struct Tld { - TldId id; - Buf *name; - VisibMod visib_mod; - AstNode *source_node; - - ZigType *import; - Scope *parent_scope; - TldResolution resolution; -}; - -struct TldVar { - Tld base; - - ZigVar *var; - Buf *extern_lib_name; - bool analyzing_type; // flag to detect dependency loops -}; - -struct TldFn { - Tld base; - - ZigFn *fn_entry; - Buf *extern_lib_name; -}; - -struct TldContainer { - Tld base; - - ScopeDecls *decls_scope; - ZigType *type_entry; -}; - -struct TldCompTime { - Tld base; -}; - -struct TldUsingNamespace { - Tld base; - - ZigValue *using_namespace_value; -}; - -struct TypeEnumField { - Buf *name; - BigInt value; - uint32_t decl_index; - AstNode *decl_node; -}; - -struct TypeUnionField { - Buf *name; - ZigType *type_entry; // available after ResolveStatusSizeKnown - ZigValue *type_val; // available after ResolveStatusZeroBitsKnown - TypeEnumField *enum_field; - AstNode *decl_node; - uint32_t gen_index; - uint32_t align; -}; - -enum NodeType { - NodeTypeFnProto, - NodeTypeFnDef, - NodeTypeParamDecl, - NodeTypeBlock, - NodeTypeGroupedExpr, - NodeTypeReturnExpr, - NodeTypeDefer, - NodeTypeVariableDeclaration, - NodeTypeTestDecl, - NodeTypeBinOpExpr, - NodeTypeCatchExpr, - NodeTypeFloatLiteral, - NodeTypeIntLiteral, - NodeTypeStringLiteral, - NodeTypeCharLiteral, - NodeTypeIdentifier, - NodeTypePrefixOpExpr, - NodeTypePointerType, - NodeTypeFnCallExpr, - NodeTypeArrayAccessExpr, - NodeTypeSliceExpr, - NodeTypeFieldAccessExpr, - NodeTypePtrDeref, - NodeTypeUnwrapOptional, - NodeTypeUsingNamespace, - NodeTypeUnreachable, - NodeTypeIfBoolExpr, - NodeTypeWhileExpr, - NodeTypeForExpr, - NodeTypeSwitchExpr, - NodeTypeSwitchProng, - NodeTypeSwitchRange, - NodeTypeCompTime, - NodeTypeNoSuspend, - NodeTypeBreak, - NodeTypeContinue, - NodeTypeAsmExpr, - NodeTypeContainerDecl, - NodeTypeStructField, - NodeTypeContainerInitExpr, - NodeTypeStructValueField, - NodeTypeArrayType, - NodeTypeInferredArrayType, - NodeTypeErrorType, - NodeTypeIfErrorExpr, - NodeTypeIfOptional, - NodeTypeErrorSetDecl, - NodeTypeErrorSetField, - NodeTypeResume, - NodeTypeAwaitExpr, - NodeTypeSuspend, - NodeTypeAnyFrameType, - // main_token points to the identifier. - NodeTypeEnumLiteral, - NodeTypeAnyTypeField, -}; - -enum FnInline { - FnInlineAuto, - FnInlineAlways, - FnInlineNever, -}; - -struct AstNodeFnProto { - Buf *name; - ZigList params; - AstNode *return_type; - AstNode *fn_def_node; - // populated if this is an extern declaration - Buf *lib_name; - // populated if the "align A" is present - AstNode *align_expr; - // populated if the "section(S)" is present - AstNode *section_expr; - // populated if the "callconv(S)" is present - AstNode *callconv_expr; - - TokenIndex doc_comments; - - // This is set based only on the existence of a noinline or inline keyword. - // This is then resolved to an is_noinline bool and (potentially .Inline) - // calling convention in resolve_decl_fn() in analyze.cpp. - FnInline fn_inline; - - VisibMod visib_mod; - bool auto_err_set; - bool is_var_args; - bool is_extern; - bool is_export; -}; - -struct AstNodeFnDef { - AstNode *fn_proto; - AstNode *body; -}; - -struct AstNodeParamDecl { - Buf *name; - AstNode *type; - TokenIndex doc_comments; - TokenIndex anytype_token; - bool is_noalias; - bool is_comptime; - bool is_var_args; -}; - -struct AstNodeBlock { - Buf *name; - ZigList statements; -}; - -enum ReturnKind { - ReturnKindUnconditional, - ReturnKindError, -}; - -struct AstNodeReturnExpr { - ReturnKind kind; - // might be null in case of return void; - AstNode *expr; -}; - -struct AstNodeDefer { - ReturnKind kind; - AstNode *err_payload; - AstNode *expr; - - // temporary data used in IR generation - Scope *child_scope; - Scope *expr_scope; -}; - -struct AstNodeVariableDeclaration { - Buf *symbol; - // one or both of type and expr will be non null - AstNode *type; - AstNode *expr; - // populated if this is an extern declaration - Buf *lib_name; - // populated if the "align(A)" is present - AstNode *align_expr; - // populated if the "section(S)" is present - AstNode *section_expr; - TokenIndex doc_comments; - - TokenIndex threadlocal_tok; - VisibMod visib_mod; - bool is_const; - bool is_comptime; - bool is_export; - bool is_extern; -}; - -struct AstNodeTestDecl { - // nullptr if the test declaration has no name - Buf *name; - - AstNode *body; -}; - -enum BinOpType { - BinOpTypeInvalid, - BinOpTypeAssign, - BinOpTypeAssignTimes, - BinOpTypeAssignTimesSat, - BinOpTypeAssignTimesWrap, - BinOpTypeAssignDiv, - BinOpTypeAssignMod, - BinOpTypeAssignPlus, - BinOpTypeAssignPlusSat, - BinOpTypeAssignPlusWrap, - BinOpTypeAssignMinus, - BinOpTypeAssignMinusSat, - BinOpTypeAssignMinusWrap, - BinOpTypeAssignBitShiftLeft, - BinOpTypeAssignBitShiftLeftSat, - BinOpTypeAssignBitShiftRight, - BinOpTypeAssignBitAnd, - BinOpTypeAssignBitXor, - BinOpTypeAssignBitOr, - BinOpTypeBoolOr, - BinOpTypeBoolAnd, - BinOpTypeCmpEq, - BinOpTypeCmpNotEq, - BinOpTypeCmpLessThan, - BinOpTypeCmpGreaterThan, - BinOpTypeCmpLessOrEq, - BinOpTypeCmpGreaterOrEq, - BinOpTypeBinOr, - BinOpTypeBinXor, - BinOpTypeBinAnd, - BinOpTypeBitShiftLeft, - BinOpTypeBitShiftLeftSat, - BinOpTypeBitShiftRight, - BinOpTypeAdd, - BinOpTypeAddSat, - BinOpTypeAddWrap, - BinOpTypeSub, - BinOpTypeSubSat, - BinOpTypeSubWrap, - BinOpTypeMult, - BinOpTypeMultSat, - BinOpTypeMultWrap, - BinOpTypeDiv, - BinOpTypeMod, - BinOpTypeUnwrapOptional, - BinOpTypeArrayCat, - BinOpTypeArrayMult, - BinOpTypeErrorUnion, - BinOpTypeMergeErrorSets, -}; - -struct AstNodeBinOpExpr { - AstNode *op1; - BinOpType bin_op; - AstNode *op2; -}; - -struct AstNodeCatchExpr { - AstNode *op1; - AstNode *symbol; // can be null - AstNode *op2; -}; - -struct AstNodeUnwrapOptional { - AstNode *expr; -}; - -// Must be synchronized with std.builtin.CallOptions.Modifier -enum CallModifier { - CallModifierNone, - CallModifierAsync, - CallModifierNeverTail, - CallModifierNeverInline, - CallModifierNoSuspend, - CallModifierAlwaysTail, - CallModifierAlwaysInline, - CallModifierCompileTime, - - // These are additional tags in the compiler, but not exposed in the std lib. - CallModifierBuiltin, -}; - -struct AstNodeFnCallExpr { - AstNode *fn_ref_expr; - ZigList params; - CallModifier modifier; - bool seen; // used by @compileLog -}; - -// Must be kept in sync with std.builtin.PrefetchOptions.Rw -enum PrefetchRw { - PrefetchRwRead, - PrefetchRwWrite, -}; - -// Must be kept in sync with std.builtin.PrefetchOptions.Cache -enum PrefetchCache { - PrefetchCacheInstruction, - PrefetchCacheData, -}; - -struct AstNodeArrayAccessExpr { - AstNode *array_ref_expr; - AstNode *subscript; -}; - -struct AstNodeSliceExpr { - AstNode *array_ref_expr; - AstNode *start; - AstNode *end; - AstNode *sentinel; // can be null -}; - -struct AstNodeFieldAccessExpr { - AstNode *struct_expr; - Buf *field_name; -}; - -struct AstNodePtrDerefExpr { - AstNode *target; -}; - -enum PrefixOp { - PrefixOpInvalid, - PrefixOpBoolNot, - PrefixOpBinNot, - PrefixOpNegation, - PrefixOpNegationWrap, - PrefixOpOptional, - PrefixOpAddrOf, -}; - -struct AstNodePrefixOpExpr { - PrefixOp prefix_op; - AstNode *primary_expr; -}; - -struct AstNodePointerType { - TokenIndex star_token; - TokenIndex allow_zero_token; - TokenIndex bit_offset_start; - TokenIndex host_int_bytes; - - AstNode *sentinel; - AstNode *align_expr; - AstNode *op_expr; - bool is_const; - bool is_volatile; -}; - -struct AstNodeInferredArrayType { - AstNode *sentinel; // can be null - AstNode *child_type; -}; - -struct AstNodeArrayType { - AstNode *size; - AstNode *sentinel; - AstNode *child_type; - AstNode *align_expr; - TokenIndex allow_zero_token; - bool is_const; - bool is_volatile; -}; - -struct AstNodeUsingNamespace { - VisibMod visib_mod; - AstNode *expr; -}; - -struct AstNodeIfBoolExpr { - AstNode *condition; - AstNode *then_block; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeTryExpr { - Buf *var_symbol; - AstNode *target_node; - AstNode *then_node; - AstNode *else_node; - Buf *err_symbol; - bool var_is_ptr; -}; - -struct AstNodeTestExpr { - Buf *var_symbol; - bool var_is_ptr; - AstNode *target_node; - AstNode *then_node; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeWhileExpr { - Buf *name; - AstNode *condition; - Buf *var_symbol; - AstNode *continue_expr; - AstNode *body; - AstNode *else_node; - Buf *err_symbol; - bool is_inline; - bool var_is_ptr; -}; - -struct AstNodeForExpr { - Buf *name; - AstNode *array_expr; - AstNode *elem_node; // always a symbol - AstNode *index_node; // always a symbol, might be null - AstNode *body; - AstNode *else_node; // can be null - bool elem_is_ptr; - bool is_inline; -}; - -struct AstNodeSwitchExpr { - AstNode *expr; - ZigList prongs; -}; - -struct AstNodeSwitchProng { - ZigList items; - AstNode *var_symbol; - AstNode *expr; - bool var_is_ptr; - bool any_items_are_range; - bool is_inline; -}; - -struct AstNodeSwitchRange { - AstNode *start; - AstNode *end; -}; - -struct AstNodeCompTime { - AstNode *expr; -}; - -struct AstNodeNoSuspend { - AstNode *expr; -}; - -struct AsmOutput { - Buf *asm_symbolic_name; - Buf *constraint; - Buf *variable_name; - AstNode *return_type; // null unless "=r" and return -}; - -struct AsmInput { - Buf *asm_symbolic_name; - Buf *constraint; - AstNode *expr; -}; - -struct SrcPos { - size_t line; - size_t column; -}; - -enum AsmTokenId { - AsmTokenIdTemplate, - AsmTokenIdPercent, - AsmTokenIdVar, - AsmTokenIdUniqueId, -}; - -struct AsmToken { - enum AsmTokenId id; - size_t start; - size_t end; -}; - -struct AstNodeAsmExpr { - TokenIndex volatile_token; - AstNode *asm_template; - ZigList output_list; - ZigList input_list; - ZigList clobber_list; -}; - -enum ContainerKind { - ContainerKindStruct, - ContainerKindEnum, - ContainerKindUnion, - ContainerKindOpaque, -}; - -enum ContainerLayout { - ContainerLayoutAuto, - ContainerLayoutExtern, - ContainerLayoutPacked, -}; - -struct AstNodeContainerDecl { - AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) - ZigList fields; - ZigList decls; - TokenIndex doc_comments; - - ContainerKind kind; - ContainerLayout layout; - - bool auto_enum, is_root; // union(enum) - bool unsupported_explicit_backing_int; -}; - -struct AstNodeErrorSetField { - TokenIndex doc_comments; - AstNode *field_name; -}; - -struct AstNodeErrorSetDecl { - // Each AstNode could be AstNodeErrorSetField or just AstNodeSymbolExpr to save memory - ZigList decls; -}; - -struct AstNodeStructField { - Buf *name; - AstNode *type; - AstNode *value; - // populated if the "align(A)" is present - AstNode *align_expr; - TokenIndex doc_comments; - TokenIndex comptime_token; -}; - -struct AstNodeStructValueField { - Buf *name; - AstNode *expr; -}; - -enum ContainerInitKind { - ContainerInitKindStruct, - ContainerInitKindArray, -}; - -struct AstNodeContainerInitExpr { - AstNode *type; - ZigList entries; - ContainerInitKind kind; -}; - -struct AstNodeIdentifier { - Buf *name; - bool is_at_syntax; -}; - -struct AstNodeEnumLiteral { - Buf *name; -}; - -struct AstNodeBreakExpr { - Buf *name; - AstNode *expr; // may be null -}; - -struct AstNodeResumeExpr { - AstNode *expr; -}; - -struct AstNodeContinueExpr { - Buf *name; -}; - -struct AstNodeAwaitExpr { - AstNode *expr; -}; - -struct AstNodeSuspend { - AstNode *block; -}; - -struct AstNodeAnyFrameType { - AstNode *payload_type; // can be NULL -}; - -struct AstNode { - enum NodeType type; - TokenIndex main_token; - ZigType *owner; - union { - AstNodeFnDef fn_def; - AstNodeFnProto fn_proto; - AstNodeParamDecl param_decl; - AstNodeBlock block; - AstNode * grouped_expr; - AstNodeReturnExpr return_expr; - AstNodeDefer defer; - AstNodeVariableDeclaration variable_declaration; - AstNodeTestDecl test_decl; - AstNodeBinOpExpr bin_op_expr; - AstNodeCatchExpr unwrap_err_expr; - AstNodeUnwrapOptional unwrap_optional; - AstNodePrefixOpExpr prefix_op_expr; - AstNodePointerType pointer_type; - AstNodeFnCallExpr fn_call_expr; - AstNodeArrayAccessExpr array_access_expr; - AstNodeSliceExpr slice_expr; - AstNodeUsingNamespace using_namespace; - AstNodeIfBoolExpr if_bool_expr; - AstNodeTryExpr if_err_expr; - AstNodeTestExpr test_expr; - AstNodeWhileExpr while_expr; - AstNodeForExpr for_expr; - AstNodeSwitchExpr switch_expr; - AstNodeSwitchProng switch_prong; - AstNodeSwitchRange switch_range; - AstNodeCompTime comptime_expr; - AstNodeNoSuspend nosuspend_expr; - AstNodeAsmExpr asm_expr; - AstNodeFieldAccessExpr field_access_expr; - AstNodePtrDerefExpr ptr_deref_expr; - AstNodeContainerDecl container_decl; - AstNodeStructField struct_field; - AstNodeContainerInitExpr container_init_expr; - AstNodeStructValueField struct_val_field; - AstNodeBreakExpr break_expr; - AstNodeContinueExpr continue_expr; - AstNodeArrayType array_type; - AstNodeInferredArrayType inferred_array_type; - AstNodeErrorSetDecl err_set_decl; - AstNodeErrorSetField err_set_field; - AstNodeResumeExpr resume_expr; - AstNodeAwaitExpr await_expr; - AstNodeSuspend suspend; - AstNodeAnyFrameType anyframe_type; - - // These are part of an astgen workaround to use less memory by - // memoizing into the AST. Once astgen is modified to only run once - // per corresponding source, this workaround can be removed. - AstNodeIdentifier identifier; - AstNodeEnumLiteral enum_literal; - } data; - - // This is a function for use in the debugger to print - // the source location. - void src(); -}; - -// this struct is allocated with allocate_nonzero -struct FnTypeParamInfo { - bool is_noalias; - ZigType *type; -}; - -struct GenericFnTypeId { - CodeGen *codegen; - ZigFn *fn_entry; - ZigValue *params; - size_t param_count; -}; - -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id); -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b); - -struct FnTypeId { - ZigType *return_type; - FnTypeParamInfo *param_info; - size_t param_count; - size_t next_param_index; - bool is_var_args; - CallingConvention cc; - uint32_t alignment; -}; - -uint32_t fn_type_id_hash(FnTypeId*); -bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); - -static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX; -static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1; - -struct InferredStructField { - ZigType *inferred_struct_type; - Buf *field_name; - bool already_resolved; -}; - -struct ZigTypePointer { - ZigType *child_type; - ZigType *slice_parent; - - // Anonymous struct literal syntax uses this when the result location has - // no type in it. This field is null if this pointer does not refer to - // a field of a currently-being-inferred struct type. - // When this is non-null, the pointer is pointing to the base of the inferred - // struct. - InferredStructField *inferred_struct_field; - - // This can be null. If it is non-null, it means the pointer is terminated by this - // sentinel value. This is most commonly used for C-style strings, with a 0 byte - // to specify the length of the memory pointed to. - ZigValue *sentinel; - - PtrLen ptr_len; - uint32_t explicit_alignment; // 0 means use ABI alignment - - uint32_t bit_offset_in_host; - // size of host integer. 0 means no host integer; this field is aligned - // when vector_index != VECTOR_INDEX_NONE this is the len of the containing vector - uint32_t host_int_bytes; - - uint32_t vector_index; // see the VECTOR_INDEX_* constants - bool is_const; - bool is_volatile; - bool allow_zero; - bool resolve_loop_flag_zero_bits; -}; - -struct ZigTypeInt { - uint32_t bit_count; - bool is_signed; -}; - -struct ZigTypeFloat { - size_t bit_count; -}; - -// Needs to have the same memory layout as ZigTypeVector -struct ZigTypeArray { - ZigType *child_type; - uint64_t len; - ZigValue *sentinel; -}; - -struct TypeStructField { - Buf *name; - ZigType *type_entry; // available after ResolveStatusSizeKnown - ZigValue *type_val; // available after ResolveStatusZeroBitsKnown - size_t src_index; - size_t gen_index; - size_t offset; // byte offset from beginning of struct - AstNode *decl_node; - ZigValue *init_val; // null and then memoized - uint32_t bit_offset_in_host; // offset from the memory at gen_index - uint32_t host_int_bytes; // size of host integer - uint32_t align; - bool is_comptime; -}; - -enum ResolveStatus { - ResolveStatusUnstarted, - ResolveStatusInvalid, - ResolveStatusBeingInferred, - ResolveStatusZeroBitsKnown, - ResolveStatusAlignmentKnown, - ResolveStatusSizeKnown, - ResolveStatusLLVMFwdDecl, - ResolveStatusLLVMFull, -}; - -struct ZigPackage { - Buf root_src_dir; - Buf root_src_path; // relative to root_src_dir - Buf pkg_path; // a.b.c.d which follows the package dependency chain from the root package - - // reminder: hash tables must be initialized before use - HashMap package_table; - - bool added_to_cache; -}; - -// Stuff that only applies to a struct which is the implicit root struct of a file -struct RootStruct { - ZigPackage *package; - Buf *path; // relative to root_package->root_src_dir - Buf *source_code; - ZigLLVMDIFile *di_file; - size_t token_count; - TokenId *token_ids; - TokenLoc *token_locs; -}; - -enum StructSpecial { - StructSpecialNone, - StructSpecialSlice, - StructSpecialInferredTuple, - StructSpecialInferredStruct, -}; - -struct ZigTypeStruct { - AstNode *decl_node; - TypeStructField **fields; - TypeStructField *misaligned_field; - ScopeDecls *decls_scope; - HashMap fields_by_name; - RootStruct *root_struct; - uint32_t *host_int_bytes; // available for packed structs, indexed by gen_index - size_t llvm_full_type_queue_index; - - uint32_t src_field_count; - uint32_t gen_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - StructSpecial special; - // whether any of the fields require comptime - // known after ResolveStatusZeroBitsKnown - bool requires_comptime; - bool resolve_loop_flag_zero_bits; - bool resolve_loop_flag_other; - bool created_by_at_type; -}; - -struct ZigTypeOptional { - ZigType *child_type; - ResolveStatus resolve_status; -}; - -struct ZigTypeErrorUnion { - ZigType *err_set_type; - ZigType *payload_type; - size_t pad_bytes; - LLVMTypeRef pad_llvm_type; -}; - -struct ZigTypeErrorSet { - ErrorTableEntry **errors; - ZigFn *infer_fn; - uint32_t err_count; - bool incomplete; -}; - -struct ZigTypeEnum { - AstNode *decl_node; - TypeEnumField *fields; - ZigType *tag_int_type; - - ScopeDecls *decls_scope; - - LLVMValueRef name_function; - - HashMap fields_by_name; - uint32_t src_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - bool has_explicit_tag_type; - bool non_exhaustive; - bool resolve_loop_flag; -}; - -uint32_t type_ptr_hash(const ZigType *ptr); -bool type_ptr_eql(const ZigType *a, const ZigType *b); - -uint32_t pkg_ptr_hash(const ZigPackage *ptr); -bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b); - -uint32_t tld_ptr_hash(const Tld *ptr); -bool tld_ptr_eql(const Tld *a, const Tld *b); - -uint32_t node_ptr_hash(const AstNode *ptr); -bool node_ptr_eql(const AstNode *a, const AstNode *b); - -uint32_t fn_ptr_hash(const ZigFn *ptr); -bool fn_ptr_eql(const ZigFn *a, const ZigFn *b); - -uint32_t err_ptr_hash(const ErrorTableEntry *ptr); -bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b); - -struct ZigTypeUnion { - AstNode *decl_node; - TypeUnionField *fields; - ScopeDecls *decls_scope; - HashMap fields_by_name; - ZigType *tag_type; // always an enum or null - LLVMTypeRef union_llvm_type; - TypeUnionField *most_aligned_union_member; - size_t gen_union_index; - size_t gen_tag_index; - size_t union_abi_size; - - uint32_t src_field_count; - uint32_t gen_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - bool have_explicit_tag_type; - // whether any of the fields require comptime - // the value is not valid until zero_bits_known == true - bool requires_comptime; - bool resolve_loop_flag_zero_bits; - bool resolve_loop_flag_other; -}; - -struct FnGenParamInfo { - size_t src_index; - size_t gen_index; - bool is_byval; - ZigType *type; -}; - -struct ZigTypeFn { - FnTypeId fn_type_id; - bool is_generic; - ZigType *gen_return_type; - size_t gen_param_count; - FnGenParamInfo *gen_param_info; - - LLVMTypeRef raw_type_ref; - ZigLLVMDIType *raw_di_type; - - ZigType *bound_fn_parent; -}; - -struct ZigTypeBoundFn { - ZigType *fn_type; -}; - -// Needs to have the same memory layout as ZigTypeArray -struct ZigTypeVector { - // The type must be a pointer, integer, bool, or float - ZigType *elem_type; - uint64_t len; - size_t padding; -}; - -// A lot of code is relying on ZigTypeArray and ZigTypeVector having the same layout/size -static_assert(sizeof(ZigTypeVector) == sizeof(ZigTypeArray), "Size of ZigTypeVector and ZigTypeArray do not match!"); - -enum ZigTypeId { - ZigTypeIdInvalid, - ZigTypeIdMetaType, - ZigTypeIdVoid, - ZigTypeIdBool, - ZigTypeIdUnreachable, - ZigTypeIdInt, - ZigTypeIdFloat, - ZigTypeIdPointer, - ZigTypeIdArray, - ZigTypeIdStruct, - ZigTypeIdComptimeFloat, - ZigTypeIdComptimeInt, - ZigTypeIdUndefined, - ZigTypeIdNull, - ZigTypeIdOptional, - ZigTypeIdErrorUnion, - ZigTypeIdErrorSet, - ZigTypeIdEnum, - ZigTypeIdUnion, - ZigTypeIdFn, - ZigTypeIdBoundFn, - ZigTypeIdOpaque, - ZigTypeIdFnFrame, - ZigTypeIdAnyFrame, - ZigTypeIdVector, - ZigTypeIdEnumLiteral, -}; - -enum OnePossibleValue { - OnePossibleValueInvalid, - OnePossibleValueNo, - OnePossibleValueYes, -}; - -struct ZigTypeOpaque { - AstNode *decl_node; - Buf *bare_name; - - ScopeDecls *decls_scope; -}; - -struct ZigTypeFnFrame { - ZigFn *fn; - ZigType *locals_struct; - - // This is set to the type that resolving the frame currently depends on, null if none. - // It's for generating a helpful error message. - ZigType *resolve_loop_type; - AstNode *resolve_loop_src_node; - bool reported_loop_err; -}; - -struct ZigTypeAnyFrame { - ZigType *result_type; // null if `anyframe` instead of `anyframe->T` - LLVMTypeRef struct_llvm_ty; -}; - -struct ZigType { - ZigTypeId id; - Buf name; - - // These are not supposed to be accessed directly. They're - // null during semantic analysis, memoized with get_llvm_type - // get_llvm_c_abi_type and get_llvm_di_type - LLVMTypeRef llvm_type; - LLVMTypeRef llvm_c_abi_type; - ZigLLVMDIType *llvm_di_type; - - union { - ZigTypePointer pointer; - ZigTypeInt integral; - ZigTypeFloat floating; - ZigTypeArray array; - ZigTypeStruct structure; - ZigTypeOptional maybe; - ZigTypeErrorUnion error_union; - ZigTypeErrorSet error_set; - ZigTypeEnum enumeration; - ZigTypeUnion unionation; - ZigTypeFn fn; - ZigTypeBoundFn bound_fn; - ZigTypeVector vector; - ZigTypeOpaque opaque; - ZigTypeFnFrame frame; - ZigTypeAnyFrame any_frame; - } data; - - // use these fields to make sure we don't duplicate type table entries for the same type - ZigType *pointer_parent[2]; // [0 - mut, 1 - const] - ZigType *optional_parent; - ZigType *any_frame_parent; - // If we generate a constant name value for this type, we memoize it here. - // The type of this is array - ZigValue *cached_const_name_val; - - OnePossibleValue one_possible_value; - // Known after ResolveStatusAlignmentKnown. - uint32_t abi_align; - // The offset in bytes between consecutive array elements of this type. Known - // after ResolveStatusSizeKnown. - size_t abi_size; - // Number of bits of information in this type. Known after ResolveStatusSizeKnown. - size_t size_in_bits; -}; - -enum FnAnalState { - FnAnalStateReady, - FnAnalStateProbing, - FnAnalStateComplete, - FnAnalStateInvalid, -}; - -struct GlobalExport { - Buf name; - GlobalLinkageId linkage; -}; - -struct ZigFn { - LLVMValueRef llvm_value; - LLVMValueRef abi_return_value; // alloca used when converting at SysV ABI boundaries - const char *llvm_name; - AstNode *proto_node; - AstNode *body_node; - ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls - Scope *child_scope; // parent is scope for last parameter - ScopeBlock *def_scope; // parent is child_scope - Buf symbol_name; - // This is the function type assuming the function does not suspend. - // Note that for an async function, this can be shared with non-async functions. So the value here - // should only be read for things in common between non-async and async function types. - ZigType *type_entry; - // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type. - // However for functions that suspend, those values could possibly be their non-suspending equivalents. - // So these values should be preferred. - LLVMTypeRef raw_type_ref; - ZigLLVMDIType *raw_di_type; - - ZigType *frame_type; - // in the case of normal functions this is the implicit return type - // in the case of async functions this is the implicit return type according to the - // zig source code, not according to zig ir - ZigType *src_implicit_return_type; - Stage1Zir *stage1_zir; - Stage1Air analyzed_executable; - size_t branch_quota; - AstNode **param_source_nodes; - Buf **param_names; - Stage1AirInst *err_code_spill; - AstNode *assumed_non_async; - - AstNode *fn_no_inline_set_node; - AstNode *fn_static_eval_set_node; - - ZigList alloca_gen_list; - ZigList variable_list; - - Buf *section_name; - AstNode *set_alignstack_node; - - AstNode *set_cold_node; - const AstNode *inferred_async_node; - ZigFn *inferred_async_fn; - AstNode *non_async_node; - - ZigList export_list; - ZigList call_list; - ZigList await_list; - - LLVMValueRef valgrind_client_request_array; - - FnAnalState anal_state; - - uint32_t align_bytes; - uint32_t alignstack_value; - - bool calls_or_awaits_errorable_fn; - bool is_cold; - bool is_noinline; -}; - -static inline bool fn_is_test(const ZigFn *fn) { - return fn->proto_node->type == NodeTypeTestDecl; -} - -uint32_t fn_table_entry_hash(ZigFn*); -bool fn_table_entry_eql(ZigFn *a, ZigFn *b); - -enum BuiltinFnId { - BuiltinFnIdInvalid, - BuiltinFnIdMemcpy, - BuiltinFnIdMemset, - BuiltinFnIdSizeof, - BuiltinFnIdAlignOf, - BuiltinFnIdField, - BuiltinFnIdTypeInfo, - BuiltinFnIdType, - BuiltinFnIdHasField, - BuiltinFnIdTypeof, - BuiltinFnIdAddWithOverflow, - BuiltinFnIdSubWithOverflow, - BuiltinFnIdMulWithOverflow, - BuiltinFnIdShlWithOverflow, - BuiltinFnIdMulAdd, - BuiltinFnIdCInclude, - BuiltinFnIdCDefine, - BuiltinFnIdCUndef, - BuiltinFnIdCompileErr, - BuiltinFnIdCompileLog, - BuiltinFnIdCtz, - BuiltinFnIdClz, - BuiltinFnIdPopCount, - BuiltinFnIdBswap, - BuiltinFnIdBitReverse, - BuiltinFnIdImport, - BuiltinFnIdCImport, - BuiltinFnIdErrName, - BuiltinFnIdBreakpoint, - BuiltinFnIdReturnAddress, - BuiltinFnIdEmbedFile, - BuiltinFnIdCmpxchgWeak, - BuiltinFnIdCmpxchgStrong, - BuiltinFnIdFence, - BuiltinFnIdDivExact, - BuiltinFnIdDivTrunc, - BuiltinFnIdDivFloor, - BuiltinFnIdRem, - BuiltinFnIdMod, - BuiltinFnIdSqrt, - BuiltinFnIdSin, - BuiltinFnIdCos, - BuiltinFnIdTan, - BuiltinFnIdExp, - BuiltinFnIdExp2, - BuiltinFnIdLog, - BuiltinFnIdLog2, - BuiltinFnIdLog10, - BuiltinFnIdFabs, - BuiltinFnIdFloor, - BuiltinFnIdCeil, - BuiltinFnIdTrunc, - BuiltinFnIdNearbyInt, - BuiltinFnIdRound, - BuiltinFnIdTruncate, - BuiltinFnIdIntCast, - BuiltinFnIdFloatCast, - BuiltinFnIdErrSetCast, - BuiltinFnIdIntToFloat, - BuiltinFnIdFloatToInt, - BuiltinFnIdBoolToInt, - BuiltinFnIdErrToInt, - BuiltinFnIdIntToErr, - BuiltinFnIdEnumToInt, - BuiltinFnIdIntToEnum, - BuiltinFnIdVectorType, - BuiltinFnIdShuffle, - BuiltinFnIdSelect, - BuiltinFnIdSplat, - BuiltinFnIdSetCold, - BuiltinFnIdSetRuntimeSafety, - BuiltinFnIdSetFloatMode, - BuiltinFnIdTypeName, - BuiltinFnIdPanic, - BuiltinFnIdPtrCast, - BuiltinFnIdBitCast, - BuiltinFnIdIntToPtr, - BuiltinFnIdPtrToInt, - BuiltinFnIdTagName, - BuiltinFnIdFieldParentPtr, - BuiltinFnIdOffsetOf, - BuiltinFnIdBitOffsetOf, - BuiltinFnIdAsyncCall, - BuiltinFnIdShlExact, - BuiltinFnIdShrExact, - BuiltinFnIdSetEvalBranchQuota, - BuiltinFnIdAlignCast, - BuiltinFnIdThis, - BuiltinFnIdSetAlignStack, - BuiltinFnIdExport, - BuiltinFnIdExtern, - BuiltinFnIdErrorReturnTrace, - BuiltinFnIdAtomicRmw, - BuiltinFnIdAtomicLoad, - BuiltinFnIdAtomicStore, - BuiltinFnIdHasDecl, - BuiltinFnIdUnionInit, - BuiltinFnIdFrameAddress, - BuiltinFnIdFrameType, - BuiltinFnIdFrameHandle, - BuiltinFnIdFrameSize, - BuiltinFnIdAs, - BuiltinFnIdCall, - BuiltinFnIdBitSizeof, - BuiltinFnIdWasmMemorySize, - BuiltinFnIdWasmMemoryGrow, - BuiltinFnIdSrc, - BuiltinFnIdReduce, - BuiltinFnIdMaximum, - BuiltinFnIdMinimum, - BuiltinFnIdPrefetch, - BuiltinFnIdAddrSpaceCast, -}; - -struct BuiltinFnEntry { - BuiltinFnId id; - Buf name; - size_t param_count; -}; - -enum PanicMsgId { - PanicMsgIdUnreachable, - PanicMsgIdBoundsCheckFailure, - PanicMsgIdCastNegativeToUnsigned, - PanicMsgIdCastTruncatedData, - PanicMsgIdIntegerOverflow, - PanicMsgIdShlOverflowedBits, - PanicMsgIdShrOverflowedBits, - PanicMsgIdDivisionByZero, - PanicMsgIdRemainderDivisionByZero, - PanicMsgIdExactDivisionRemainder, - PanicMsgIdUnwrapOptionalFail, - PanicMsgIdInvalidErrorCode, - PanicMsgIdIncorrectAlignment, - PanicMsgIdBadUnionField, - PanicMsgIdBadEnumValue, - PanicMsgIdFloatToInt, - PanicMsgIdPtrCastNull, - PanicMsgIdBadResume, - PanicMsgIdBadAwait, - PanicMsgIdBadReturn, - PanicMsgIdResumedAnAwaitingFn, - PanicMsgIdFrameTooSmall, - PanicMsgIdResumedFnPendingAwait, - PanicMsgIdBadNoSuspendCall, - PanicMsgIdResumeNotSuspendedFn, - PanicMsgIdBadSentinel, - PanicMsgIdShxTooBigRhs, - - PanicMsgIdCount, -}; - -uint32_t fn_eval_hash(Scope*); -bool fn_eval_eql(Scope *a, Scope *b); - -struct TypeId { - ZigTypeId id; - - union { - struct { - CodeGen *codegen; - ZigType *child_type; - InferredStructField *inferred_struct_field; - ZigValue *sentinel; - PtrLen ptr_len; - uint32_t alignment; - - uint32_t bit_offset_in_host; - uint32_t host_int_bytes; - - uint32_t vector_index; - bool is_const; - bool is_volatile; - bool allow_zero; - } pointer; - struct { - CodeGen *codegen; - ZigType *child_type; - uint64_t size; - ZigValue *sentinel; - } array; - struct { - bool is_signed; - uint32_t bit_count; - } integer; - struct { - ZigType *err_set_type; - ZigType *payload_type; - } error_union; - struct { - ZigType *elem_type; - uint32_t len; - } vector; - } data; -}; - -uint32_t type_id_hash(TypeId const *); -bool type_id_eql(TypeId const *a, TypeId const *b); - -enum ZigLLVMFnId { - ZigLLVMFnIdCtz, - ZigLLVMFnIdClz, - ZigLLVMFnIdPopCount, - ZigLLVMFnIdOverflowArithmetic, - ZigLLVMFnIdFMA, - ZigLLVMFnIdFloatOp, - ZigLLVMFnIdBswap, - ZigLLVMFnIdBitReverse, -}; - -// There are a bunch of places in code that rely on these values being in -// exactly this order. -enum AddSubMul { - AddSubMulAdd = 0, - AddSubMulSub = 1, - AddSubMulMul = 2, -}; - -struct ZigLLVMFnKey { - ZigLLVMFnId id; - - union { - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } ctz; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } clz; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } pop_count; - struct { - BuiltinFnId op; - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } floating; - struct { - AddSubMul add_sub_mul; - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - bool is_signed; - } overflow_arithmetic; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } bswap; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } bit_reverse; - } data; -}; - -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *); -bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b); - -struct TimeEvent { - double time; - const char *name; -}; - -struct CFile { - ZigList args; - const char *source_path; - const char *preprocessor_only_basename; -}; - -struct CodeGen { - // Other code depends on this being first. - ZigStage1 stage1; - - // arena allocator destroyed just prior to codegen emit - heap::ArenaAllocator *pass1_arena; - - //////////////////////////// Runtime State - LLVMModuleRef module; - ZigList errors; - ErrorMsg *trace_err; - LLVMBuilderRef builder; - ZigLLVMDIBuilder *dbuilder; - ZigLLVMDICompileUnit *compile_unit; - ZigLLVMDIFile *compile_unit_file; - LLVMTargetDataRef target_data_ref; - LLVMTargetMachineRef target_machine; - ZigLLVMDIFile *dummy_di_file; - LLVMValueRef cur_ret_ptr; - LLVMValueRef cur_frame_ptr; - LLVMValueRef cur_fn_val; - LLVMValueRef cur_async_switch_instr; - LLVMValueRef cur_async_resume_index_ptr; - LLVMValueRef cur_async_awaiter_ptr; - LLVMBasicBlockRef cur_preamble_llvm_block; - size_t cur_resume_block_count; - LLVMValueRef cur_err_ret_trace_val_arg; - LLVMValueRef cur_err_ret_trace_val_stack; - LLVMValueRef cur_bad_not_suspended_index; - LLVMValueRef memcpy_fn_val; - LLVMValueRef memset_fn_val; - LLVMValueRef trap_fn_val; - LLVMValueRef return_address_fn_val; - LLVMValueRef frame_address_fn_val; - LLVMValueRef add_error_return_trace_addr_fn_val; - LLVMValueRef stacksave_fn_val; - LLVMValueRef stackrestore_fn_val; - LLVMValueRef write_register_fn_val; - LLVMValueRef merge_err_ret_traces_fn_val; - LLVMValueRef sp_md_node; - LLVMValueRef err_name_table; - LLVMValueRef safety_crash_err_fn; - LLVMValueRef return_err_fn; - LLVMValueRef wasm_memory_size; - LLVMValueRef wasm_memory_grow; - LLVMValueRef prefetch; - LLVMTypeRef anyframe_fn_type; - LLVMTypeRef any_frame_header_llvm_ty; - - // reminder: hash tables must be initialized before use - HashMap import_table; - HashMap builtin_fn_table; - HashMap primitive_type_table; - HashMap type_table; - HashMap fn_type_table; - HashMap error_table; - HashMap generic_table; - HashMap memoized_fn_eval_table; - HashMap llvm_fn_table; - HashMap exported_symbol_names; - HashMap external_symbol_names; - HashMap string_literals_table; - HashMap type_info_cache; - HashMap one_possible_values; - - ZigList resolve_queue; - size_t resolve_queue_index; - ZigList timing_events; - ZigList inline_fns; - ZigList test_fns; - ZigList errors_by_index; - size_t largest_err_name_len; - ZigList type_resolve_stack; - - ZigPackage *std_package; - ZigPackage *test_runner_package; - ZigPackage *compile_var_package; - ZigPackage *root_pkg; // @import("root") - ZigPackage *main_pkg; // usually same as root_pkg, except for `zig test` - ZigType *compile_var_import; - ZigType *root_import; - ZigType *start_import; - ZigType *std_builtin_import; - - struct { - ZigType *entry_bool; - ZigType *entry_c_int[CIntTypeCount]; - ZigType *entry_c_longdouble; - ZigType *entry_anyopaque; - ZigType *entry_u8; - ZigType *entry_u16; - ZigType *entry_u32; - ZigType *entry_u29; - ZigType *entry_u64; - ZigType *entry_i8; - ZigType *entry_i32; - ZigType *entry_i64; - ZigType *entry_isize; - ZigType *entry_usize; - ZigType *entry_f16; - ZigType *entry_f32; - ZigType *entry_f64; - ZigType *entry_f80; - ZigType *entry_f128; - ZigType *entry_void; - ZigType *entry_unreachable; - ZigType *entry_type; - ZigType *entry_invalid; - ZigType *entry_block; - ZigType *entry_num_lit_int; - ZigType *entry_num_lit_float; - ZigType *entry_undef; - ZigType *entry_null; - ZigType *entry_anytype; - ZigType *entry_global_error_set; - ZigType *entry_enum_literal; - ZigType *entry_any_frame; - ZigType *entry_opt_ptr_const_anyopaque; - } builtin_types; - - struct Intern { - ZigValue x_undefined; - ZigValue x_void; - ZigValue x_null; - ZigValue x_unreachable; - ZigValue zero_byte; - - ZigValue *for_undefined(); - ZigValue *for_void(); - ZigValue *for_null(); - ZigValue *for_unreachable(); - ZigValue *for_zero_byte(); - } intern; - - ZigType *align_amt_type; - ZigType *stack_trace_type; - ZigType *err_tag_type; - ZigType *test_fn_type; - - Buf llvm_triple_str; - Buf global_asm; - Buf o_file_output_path; - Buf h_file_output_path; - Buf asm_file_output_path; - Buf llvm_ir_file_output_path; - Buf bitcode_file_output_path; - - Buf *builtin_zig_path; - - Stage1ZirInst *invalid_inst_src; - Stage1AirInst *invalid_inst_gen; - Stage1AirInst *unreach_instruction; - - ZigValue panic_msg_vals[PanicMsgIdCount]; - - // The function definitions this module includes. - ZigList fn_defs; - size_t fn_defs_index; - ZigList global_vars; - - ZigFn *cur_fn; - ZigFn *panic_fn; - - ZigFn *largest_frame_fn; - - Stage2ProgressNode *main_progress_node; - Stage2ProgressNode *sub_progress_node; - - ErrColor err_color; - uint32_t next_unresolved_index; - unsigned pointer_size_bytes; - bool is_big_endian; - bool have_err_ret_tracing; - bool verbose_ir; - bool verbose_llvm_ir; - bool verbose_cimport; - bool verbose_llvm_cpu_features; - bool error_during_imports; - bool generate_error_name_table; - bool enable_time_report; - bool enable_stack_report; - bool reported_bad_link_libc_error; - bool need_frame_size_prefix_data; - bool link_libc; - bool link_libcpp; - - BuildMode build_mode; - const ZigTarget *zig_target; - TargetSubsystem subsystem; // careful using this directly; see detect_subsystem - CodeModel code_model; - bool strip_debug_symbols; - bool is_test_build; - bool is_single_threaded; - bool have_pic; - bool have_pie; - bool have_lto; - bool unwind_tables; - bool link_mode_dynamic; - bool dll_export_fns; - bool have_stack_probing; - bool red_zone; - bool omit_frame_pointer; - bool function_sections; - bool include_compiler_rt; - bool test_is_evented; - bool valgrind_enabled; - bool tsan_enabled; - - Buf *root_out_name; - Buf *test_filter; - Buf *test_name_prefix; - Buf *zig_lib_dir; - Buf *zig_std_dir; -}; - -struct ZigVar { - const char *name; - ZigValue *const_value; - ZigType *var_type; - LLVMValueRef value_ref; - Stage1ZirInst *is_comptime; - Stage1AirInst *ptr_instruction; - // which node is the declaration of the variable - AstNode *decl_node; - ZigLLVMDILocalVariable *di_loc_var; - size_t src_arg_index; - Scope *parent_scope; - Scope *child_scope; - LLVMValueRef param_value_ref; - - Buf *section_name; - - // In an inline loop, multiple variables may be created, - // In this case, a reference to a variable should follow - // this pointer to the redefined variable. - ZigVar *next_var; - - ZigList export_list; - - uint32_t align_bytes; - uint32_t ref_count; - - bool shadowable; - bool src_is_const; - bool gen_is_const; - bool is_thread_local; - bool is_comptime_memoized; - bool is_comptime_memoized_value; - bool did_the_decl_codegen; -}; - -struct ErrorTableEntry { - Buf name; - uint32_t value; - AstNode *decl_node; - ErrorTableEntry *other; // null, or another error decl that was merged into this - ZigType *set_with_only_this_in_it; - // If we generate a constant error name value for this error, we memoize it here. - // The type of this is array - ZigValue *cached_error_name_val; -}; - -enum ScopeId { - ScopeIdDecls, - ScopeIdBlock, - ScopeIdDefer, - ScopeIdDeferExpr, - ScopeIdVarDecl, - ScopeIdCImport, - ScopeIdLoop, - ScopeIdSuspend, - ScopeIdFnDef, - ScopeIdCompTime, - ScopeIdRuntime, - ScopeIdTypeOf, - ScopeIdExpr, - ScopeIdNoSuspend, -}; - -struct Scope { - CodeGen *codegen; - AstNode *source_node; - - // if the scope has a parent, this is it - Scope *parent; - - ZigLLVMDIScope *di_scope; - ScopeId id; -}; - -// This scope comes from global declarations or from -// declarations in a container declaration -// NodeTypeContainerDecl -struct ScopeDecls { - Scope base; - - HashMap decl_table; - ZigList use_decls; - AstNode *safety_set_node; - AstNode *fast_math_set_node; - ZigType *import; - // If this is a scope from a container, this is the type entry, otherwise null - ZigType *container_type; - Buf *bare_name; - - bool safety_off; - bool fast_math_on; - bool any_imports_failed; -}; - -enum LVal { - LValNone, - LValPtr, - LValAssign, -}; - -// This scope comes from a block expression in user code. -// NodeTypeBlock -struct ScopeBlock { - Scope base; - - Buf *name; - Stage1ZirBasicBlock *end_block; - Stage1ZirInst *is_comptime; - ResultLocPeerParent *peer_parent; - ZigList *incoming_values; - ZigList *incoming_blocks; - - AstNode *safety_set_node; - AstNode *fast_math_set_node; - - LVal lval; - bool safety_off; - bool fast_math_on; - bool name_used; -}; - -// This scope is created from every defer expression. -// It's the code following the defer statement. -// NodeTypeDefer -struct ScopeDefer { - Scope base; -}; - -// This scope is created from every defer expression. -// It's the parent of the defer expression itself. -// NodeTypeDefer -struct ScopeDeferExpr { - Scope base; - - bool reported_err; -}; - -// This scope is created for every variable declaration inside an IrExecutable -// NodeTypeVariableDeclaration, NodeTypeParamDecl -struct ScopeVarDecl { - Scope base; - - // The variable that creates this scope - ZigVar *var; -}; - -// This scope is created for a @cImport -// NodeTypeFnCallExpr -struct ScopeCImport { - Scope base; - - Buf buf; -}; - -// This scope is created for a loop such as for or while in order to -// make break and continue statements work. -// NodeTypeForExpr or NodeTypeWhileExpr -struct ScopeLoop { - Scope base; - - LVal lval; - Buf *name; - Stage1ZirBasicBlock *break_block; - Stage1ZirBasicBlock *continue_block; - Stage1ZirInst *is_comptime; - ZigList *incoming_values; - ZigList *incoming_blocks; - ResultLocPeerParent *peer_parent; - ScopeExpr *spill_scope; - - bool name_used; -}; - -// This scope blocks certain things from working such as comptime continue -// inside a runtime if expression. -// NodeTypeIfBoolExpr, NodeTypeWhileExpr, NodeTypeForExpr -struct ScopeRuntime { - Scope base; - - Stage1ZirInst *is_comptime; -}; - -// This scope is created for a suspend block in order to have labeled -// suspend for breaking out of a suspend and for detecting if a suspend -// block is inside a suspend block. -struct ScopeSuspend { - Scope base; - - bool reported_err; -}; - -// This scope is created for a comptime expression. -// NodeTypeCompTime, NodeTypeSwitchExpr -struct ScopeCompTime { - Scope base; -}; - -// This scope is created for a nosuspend expression. -// NodeTypeNoSuspend -struct ScopeNoSuspend { - Scope base; -}; - -// This scope is created for a function definition. -// NodeTypeFnDef -struct ScopeFnDef { - Scope base; - - ZigFn *fn_entry; -}; - -// This scope is created for a @TypeOf. -// All runtime side-effects are elided within it. -// NodeTypeFnCallExpr -struct ScopeTypeOf { - Scope base; -}; - -enum MemoizedBool { - MemoizedBoolUnknown, - MemoizedBoolFalse, - MemoizedBoolTrue, -}; - -// This scope is created for each expression. -// It's used to identify when an instruction needs to be spilled, -// so that it can be accessed after a suspend point. -struct ScopeExpr { - Scope base; - - ScopeExpr **children_ptr; - size_t children_len; - - MemoizedBool need_spill; - // This is a hack. I apologize for this, I need this to work so that I - // can make progress on other fronts. I'll pay off this tech debt eventually. - bool spill_harder; -}; - -// synchronized with code in define_builtin_compile_vars -enum AtomicOrder { - AtomicOrderUnordered, - AtomicOrderMonotonic, - AtomicOrderAcquire, - AtomicOrderRelease, - AtomicOrderAcqRel, - AtomicOrderSeqCst, -}; - -// synchronized with code in define_builtin_compile_vars -enum ReduceOp { - ReduceOp_and, - ReduceOp_or, - ReduceOp_xor, - ReduceOp_min, - ReduceOp_max, - ReduceOp_add, - ReduceOp_mul, -}; - -// synchronized with the code in define_builtin_compile_vars -enum AtomicRmwOp { - AtomicRmwOp_xchg, - AtomicRmwOp_add, - AtomicRmwOp_sub, - AtomicRmwOp_and, - AtomicRmwOp_nand, - AtomicRmwOp_or, - AtomicRmwOp_xor, - AtomicRmwOp_max, - AtomicRmwOp_min, -}; - -// A basic block contains no branching. Branches send control flow -// to another basic block. -// Phi instructions must be first in a basic block. -// The last instruction in a basic block must be of type unreachable. -struct Stage1ZirBasicBlock { - ZigList instruction_list; - Stage1AirBasicBlock *child; - Scope *scope; - const char *name_hint; - Stage1ZirInst *suspend_instruction_ref; - - uint32_t ref_count; - uint32_t index; // index into the basic block list - - uint32_t debug_id; - bool suspended; - bool in_resume_stack; -}; - -struct Stage1AirBasicBlock { - ZigList instruction_list; - Scope *scope; - const char *name_hint; - LLVMBasicBlockRef llvm_block; - LLVMBasicBlockRef llvm_exit_block; - // The instruction that referenced this basic block and caused us to - // analyze the basic block. If the same instruction wants us to emit - // the same basic block, then we re-generate it instead of saving it. - Stage1ZirInst *ref_instruction; - // When this is non-null, a branch to this basic block is only allowed - // if the branch is comptime. The instruction points to the reason - // the basic block must be comptime. - AstNode *must_be_comptime_source_node; - - uint32_t debug_id; - bool already_appended; -}; - -// Src instructions are generated by ir_gen_* functions in ir.cpp from AST. -// ir_analyze_* functions consume Src instructions and produce Gen instructions. -// Src instructions do not have type information; Gen instructions do. -enum Stage1ZirInstId : uint8_t { - Stage1ZirInstIdInvalid, - Stage1ZirInstIdDeclVar, - Stage1ZirInstIdBr, - Stage1ZirInstIdCondBr, - Stage1ZirInstIdSwitchBr, - Stage1ZirInstIdSwitchVar, - Stage1ZirInstIdSwitchElseVar, - Stage1ZirInstIdSwitchTarget, - Stage1ZirInstIdPhi, - Stage1ZirInstIdUnOp, - Stage1ZirInstIdBinOp, - Stage1ZirInstIdMergeErrSets, - Stage1ZirInstIdLoadPtr, - Stage1ZirInstIdStorePtr, - Stage1ZirInstIdFieldPtr, - Stage1ZirInstIdElemPtr, - Stage1ZirInstIdVarPtr, - Stage1ZirInstIdCall, - Stage1ZirInstIdCallArgs, - Stage1ZirInstIdCallExtra, - Stage1ZirInstIdAsyncCallExtra, - Stage1ZirInstIdConst, - Stage1ZirInstIdReturn, - Stage1ZirInstIdContainerInitList, - Stage1ZirInstIdContainerInitFields, - Stage1ZirInstIdUnreachable, - Stage1ZirInstIdTypeOf, - Stage1ZirInstIdSetCold, - Stage1ZirInstIdSetRuntimeSafety, - Stage1ZirInstIdSetFloatMode, - Stage1ZirInstIdArrayType, - Stage1ZirInstIdAnyFrameType, - Stage1ZirInstIdSliceType, - Stage1ZirInstIdAsm, - Stage1ZirInstIdSizeOf, - Stage1ZirInstIdTestNonNull, - Stage1ZirInstIdOptionalUnwrapPtr, - Stage1ZirInstIdClz, - Stage1ZirInstIdCtz, - Stage1ZirInstIdPopCount, - Stage1ZirInstIdBswap, - Stage1ZirInstIdBitReverse, - Stage1ZirInstIdImport, - Stage1ZirInstIdCImport, - Stage1ZirInstIdCInclude, - Stage1ZirInstIdCDefine, - Stage1ZirInstIdCUndef, - Stage1ZirInstIdRef, - Stage1ZirInstIdCompileErr, - Stage1ZirInstIdCompileLog, - Stage1ZirInstIdErrName, - Stage1ZirInstIdEmbedFile, - Stage1ZirInstIdCmpxchg, - Stage1ZirInstIdFence, - Stage1ZirInstIdReduce, - Stage1ZirInstIdTruncate, - Stage1ZirInstIdIntCast, - Stage1ZirInstIdFloatCast, - Stage1ZirInstIdIntToFloat, - Stage1ZirInstIdFloatToInt, - Stage1ZirInstIdBoolToInt, - Stage1ZirInstIdVectorType, - Stage1ZirInstIdShuffleVector, - Stage1ZirInstIdSelect, - Stage1ZirInstIdSplat, - Stage1ZirInstIdBoolNot, - Stage1ZirInstIdMemset, - Stage1ZirInstIdMemcpy, - Stage1ZirInstIdSlice, - Stage1ZirInstIdBreakpoint, - Stage1ZirInstIdReturnAddress, - Stage1ZirInstIdFrameAddress, - Stage1ZirInstIdFrameHandle, - Stage1ZirInstIdFrameType, - Stage1ZirInstIdFrameSize, - Stage1ZirInstIdAlignOf, - Stage1ZirInstIdOverflowOp, - Stage1ZirInstIdTestErr, - Stage1ZirInstIdMulAdd, - Stage1ZirInstIdFloatOp, - Stage1ZirInstIdUnwrapErrCode, - Stage1ZirInstIdUnwrapErrPayload, - Stage1ZirInstIdFnProto, - Stage1ZirInstIdTestComptime, - Stage1ZirInstIdPtrCast, - Stage1ZirInstIdBitCast, - Stage1ZirInstIdIntToPtr, - Stage1ZirInstIdPtrToInt, - Stage1ZirInstIdIntToEnum, - Stage1ZirInstIdEnumToInt, - Stage1ZirInstIdIntToErr, - Stage1ZirInstIdErrToInt, - Stage1ZirInstIdCheckSwitchProngsUnderYes, - Stage1ZirInstIdCheckSwitchProngsUnderNo, - Stage1ZirInstIdCheckStatementIsVoid, - Stage1ZirInstIdTypeName, - Stage1ZirInstIdDeclRef, - Stage1ZirInstIdPanic, - Stage1ZirInstIdTagName, - Stage1ZirInstIdFieldParentPtr, - Stage1ZirInstIdOffsetOf, - Stage1ZirInstIdBitOffsetOf, - Stage1ZirInstIdTypeInfo, - Stage1ZirInstIdType, - Stage1ZirInstIdHasField, - Stage1ZirInstIdSetEvalBranchQuota, - Stage1ZirInstIdPtrType, - Stage1ZirInstIdPtrTypeSimple, - Stage1ZirInstIdPtrTypeSimpleConst, - Stage1ZirInstIdAlignCast, - Stage1ZirInstIdImplicitCast, - Stage1ZirInstIdResolveResult, - Stage1ZirInstIdResetResult, - Stage1ZirInstIdSetAlignStack, - Stage1ZirInstIdArgTypeAllowVarFalse, - Stage1ZirInstIdArgTypeAllowVarTrue, - Stage1ZirInstIdExport, - Stage1ZirInstIdExtern, - Stage1ZirInstIdErrorReturnTrace, - Stage1ZirInstIdErrorUnion, - Stage1ZirInstIdAtomicRmw, - Stage1ZirInstIdAtomicLoad, - Stage1ZirInstIdAtomicStore, - Stage1ZirInstIdSaveErrRetAddr, - Stage1ZirInstIdAddImplicitReturnType, - Stage1ZirInstIdErrSetCast, - Stage1ZirInstIdCheckRuntimeScope, - Stage1ZirInstIdHasDecl, - Stage1ZirInstIdUndeclaredIdent, - Stage1ZirInstIdAlloca, - Stage1ZirInstIdEndExpr, - Stage1ZirInstIdUnionInitNamedField, - Stage1ZirInstIdSuspendBegin, - Stage1ZirInstIdSuspendFinish, - Stage1ZirInstIdAwait, - Stage1ZirInstIdResume, - Stage1ZirInstIdSpillBegin, - Stage1ZirInstIdSpillEnd, - Stage1ZirInstIdWasmMemorySize, - Stage1ZirInstIdWasmMemoryGrow, - Stage1ZirInstIdSrc, - Stage1ZirInstIdPrefetch, - Stage1ZirInstIdAddrSpaceCast, -}; - -// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. -// Src instructions do not have type information; Gen instructions do. -enum Stage1AirInstId : uint8_t { - Stage1AirInstIdInvalid, - Stage1AirInstIdDeclVar, - Stage1AirInstIdBr, - Stage1AirInstIdCondBr, - Stage1AirInstIdSwitchBr, - Stage1AirInstIdPhi, - Stage1AirInstIdBinaryNot, - Stage1AirInstIdNegation, - Stage1AirInstIdBinOp, - Stage1AirInstIdLoadPtr, - Stage1AirInstIdStorePtr, - Stage1AirInstIdVectorStoreElem, - Stage1AirInstIdStructFieldPtr, - Stage1AirInstIdUnionFieldPtr, - Stage1AirInstIdElemPtr, - Stage1AirInstIdVarPtr, - Stage1AirInstIdReturnPtr, - Stage1AirInstIdCall, - Stage1AirInstIdReturn, - Stage1AirInstIdCast, - Stage1AirInstIdUnreachable, - Stage1AirInstIdAsm, - Stage1AirInstIdTestNonNull, - Stage1AirInstIdOptionalUnwrapPtr, - Stage1AirInstIdOptionalWrap, - Stage1AirInstIdUnionTag, - Stage1AirInstIdClz, - Stage1AirInstIdCtz, - Stage1AirInstIdPopCount, - Stage1AirInstIdBswap, - Stage1AirInstIdBitReverse, - Stage1AirInstIdRef, - Stage1AirInstIdErrName, - Stage1AirInstIdCmpxchg, - Stage1AirInstIdFence, - Stage1AirInstIdReduce, - Stage1AirInstIdTruncate, - Stage1AirInstIdShuffleVector, - Stage1AirInstIdSelect, - Stage1AirInstIdSplat, - Stage1AirInstIdBoolNot, - Stage1AirInstIdMemset, - Stage1AirInstIdMemcpy, - Stage1AirInstIdSlice, - Stage1AirInstIdBreakpoint, - Stage1AirInstIdReturnAddress, - Stage1AirInstIdFrameAddress, - Stage1AirInstIdFrameHandle, - Stage1AirInstIdFrameSize, - Stage1AirInstIdOverflowOp, - Stage1AirInstIdTestErr, - Stage1AirInstIdMulAdd, - Stage1AirInstIdFloatOp, - Stage1AirInstIdUnwrapErrCode, - Stage1AirInstIdUnwrapErrPayload, - Stage1AirInstIdErrWrapCode, - Stage1AirInstIdErrWrapPayload, - Stage1AirInstIdPtrCast, - Stage1AirInstIdBitCast, - Stage1AirInstIdWidenOrShorten, - Stage1AirInstIdIntToPtr, - Stage1AirInstIdPtrToInt, - Stage1AirInstIdIntToEnum, - Stage1AirInstIdIntToErr, - Stage1AirInstIdErrToInt, - Stage1AirInstIdPanic, - Stage1AirInstIdTagName, - Stage1AirInstIdFieldParentPtr, - Stage1AirInstIdAlignCast, - Stage1AirInstIdErrorReturnTrace, - Stage1AirInstIdAtomicRmw, - Stage1AirInstIdAtomicLoad, - Stage1AirInstIdAtomicStore, - Stage1AirInstIdSaveErrRetAddr, - Stage1AirInstIdVectorToArray, - Stage1AirInstIdArrayToVector, - Stage1AirInstIdAssertZero, - Stage1AirInstIdAssertNonNull, - Stage1AirInstIdPtrOfArrayToSlice, - Stage1AirInstIdSuspendBegin, - Stage1AirInstIdSuspendFinish, - Stage1AirInstIdAwait, - Stage1AirInstIdResume, - Stage1AirInstIdSpillBegin, - Stage1AirInstIdSpillEnd, - Stage1AirInstIdVectorExtractElem, - Stage1AirInstIdAlloca, - Stage1AirInstIdConst, - Stage1AirInstIdWasmMemorySize, - Stage1AirInstIdWasmMemoryGrow, - Stage1AirInstIdExtern, - Stage1AirInstIdPrefetch, -}; - -struct Stage1ZirInst { - Stage1ZirInstId id; - uint16_t ref_count; - uint32_t debug_id; - - Scope *scope; - AstNode *source_node; - - // When analyzing IR, instructions that point to this instruction in the "old ir" - // can find the instruction that corresponds to this value in the "new ir" - // with this child field. - Stage1AirInst *child; - Stage1ZirBasicBlock *owner_bb; - - // for debugging purposes, these are useful to call to inspect the instruction - void dump(); - void src(); -}; - -struct Stage1AirInst { - Stage1AirInstId id; - // if ref_count is zero and the instruction has no side effects, - // the instruction can be omitted in codegen - uint16_t ref_count; - uint32_t debug_id; - - Scope *scope; - AstNode *source_node; - - LLVMValueRef llvm_value; - ZigValue *value; - // Nearly any instruction can have to be stored as a local variable before suspending - // and then loaded after resuming, in case there is an expression with a suspend point - // in it, such as: x + await y - Stage1AirInst *spill; - - // for debugging purposes, these are useful to call to inspect the instruction - void dump(); - void src(); -}; - -struct Stage1ZirInstDeclVar { - Stage1ZirInst base; - - ZigVar *var; - Stage1ZirInst *var_type; - Stage1ZirInst *align_value; - Stage1ZirInst *ptr; -}; - -struct Stage1AirInstDeclVar { - Stage1AirInst base; - - ZigVar *var; - Stage1AirInst *var_ptr; -}; - -struct Stage1ZirInstCondBr { - Stage1ZirInst base; - - Stage1ZirInst *condition; - Stage1ZirBasicBlock *then_block; - Stage1ZirBasicBlock *else_block; - Stage1ZirInst *is_comptime; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCondBr { - Stage1AirInst base; - - Stage1AirInst *condition; - Stage1AirBasicBlock *then_block; - Stage1AirBasicBlock *else_block; -}; - -struct Stage1ZirInstBr { - Stage1ZirInst base; - - Stage1ZirBasicBlock *dest_block; - Stage1ZirInst *is_comptime; -}; - -struct Stage1AirInstBr { - Stage1AirInst base; - - Stage1AirBasicBlock *dest_block; -}; - -struct Stage1ZirInstSwitchBrCase { - Stage1ZirInst *value; - Stage1ZirBasicBlock *block; -}; - -struct Stage1ZirInstSwitchBr { - Stage1ZirInst base; - - Stage1ZirInst *target_value; - Stage1ZirBasicBlock *else_block; - size_t case_count; - Stage1ZirInstSwitchBrCase *cases; - Stage1ZirInst *is_comptime; - Stage1ZirInst *switch_prongs_void; -}; - -struct Stage1AirInstSwitchBrCase { - Stage1AirInst *value; - Stage1AirBasicBlock *block; -}; - -struct Stage1AirInstSwitchBr { - Stage1AirInst base; - - Stage1AirInst *target_value; - Stage1AirBasicBlock *else_block; - size_t case_count; - Stage1AirInstSwitchBrCase *cases; -}; - -struct Stage1ZirInstSwitchVar { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; - Stage1ZirInst **prongs_ptr; - size_t prongs_len; -}; - -struct Stage1ZirInstSwitchElseVar { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; - Stage1ZirInstSwitchBr *switch_br; -}; - -struct Stage1ZirInstSwitchTarget { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; -}; - -struct Stage1ZirInstPhi { - Stage1ZirInst base; - - size_t incoming_count; - bool merge_comptime; - Stage1ZirBasicBlock **incoming_blocks; - Stage1ZirInst **incoming_values; - ResultLocPeerParent *peer_parent; -}; - -struct Stage1AirInstPhi { - Stage1AirInst base; - - size_t incoming_count; - Stage1AirBasicBlock **incoming_blocks; - Stage1AirInst **incoming_values; -}; - -enum IrUnOp { - IrUnOpInvalid, - IrUnOpBinNot, - IrUnOpNegation, - IrUnOpNegationWrap, - IrUnOpDereference, - IrUnOpOptional, -}; - -struct Stage1ZirInstUnOp { - Stage1ZirInst base; - - IrUnOp op_id; - LVal lval; - Stage1ZirInst *value; - ResultLoc *result_loc; -}; - -struct Stage1AirInstBinaryNot { - Stage1AirInst base; - Stage1AirInst *operand; -}; - -struct Stage1AirInstNegation { - Stage1AirInst base; - Stage1AirInst *operand; - bool wrapping; -}; - -enum IrBinOp { - IrBinOpInvalid, - IrBinOpBoolOr, - IrBinOpBoolAnd, - IrBinOpCmpEq, - IrBinOpCmpNotEq, - IrBinOpCmpLessThan, - IrBinOpCmpGreaterThan, - IrBinOpCmpLessOrEq, - IrBinOpCmpGreaterOrEq, - IrBinOpBinOr, - IrBinOpBinXor, - IrBinOpBinAnd, - IrBinOpBitShiftLeftLossy, - IrBinOpBitShiftLeftExact, - IrBinOpBitShiftRightLossy, - IrBinOpBitShiftRightExact, - IrBinOpAdd, - IrBinOpAddWrap, - IrBinOpSub, - IrBinOpSubWrap, - IrBinOpMult, - IrBinOpMultWrap, - IrBinOpDivUnspecified, - IrBinOpDivExact, - IrBinOpDivTrunc, - IrBinOpDivFloor, - IrBinOpRemUnspecified, - IrBinOpRemRem, - IrBinOpRemMod, - IrBinOpArrayCat, - IrBinOpArrayMult, - IrBinOpMax, - IrBinOpMin, - IrBinOpAddSat, - IrBinOpSubSat, - IrBinOpMultSat, - IrBinOpShlSat, -}; - -struct Stage1ZirInstBinOp { - Stage1ZirInst base; - - Stage1ZirInst *op1; - Stage1ZirInst *op2; - IrBinOp op_id; - bool safety_check_on; -}; - -struct Stage1AirInstBinOp { - Stage1AirInst base; - - Stage1AirInst *op1; - Stage1AirInst *op2; - IrBinOp op_id; - bool safety_check_on; -}; - -struct Stage1ZirInstMergeErrSets { - Stage1ZirInst base; - - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Buf *type_name; -}; - -struct Stage1ZirInstLoadPtr { - Stage1ZirInst base; - - Stage1ZirInst *ptr; -}; - -struct Stage1AirInstLoadPtr { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstStorePtr { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *value; - - bool allow_write_through_const; -}; - -struct Stage1AirInstStorePtr { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *value; -}; - -struct Stage1AirInstVectorStoreElem { - Stage1AirInst base; - - Stage1AirInst *vector_ptr; - Stage1AirInst *index; - Stage1AirInst *value; -}; - -struct Stage1ZirInstFieldPtr { - Stage1ZirInst base; - - Stage1ZirInst *container_ptr; - Buf *field_name_buffer; - Stage1ZirInst *field_name_expr; - bool initializing; -}; - -struct Stage1AirInstStructFieldPtr { - Stage1AirInst base; - - Stage1AirInst *struct_ptr; - TypeStructField *field; - bool is_const; -}; - -struct Stage1AirInstUnionFieldPtr { - Stage1AirInst base; - - Stage1AirInst *union_ptr; - TypeUnionField *field; - bool safety_check_on; - bool initializing; -}; - -struct Stage1ZirInstElemPtr { - Stage1ZirInst base; - - Stage1ZirInst *array_ptr; - Stage1ZirInst *elem_index; - AstNode *init_array_type_source_node; - PtrLen ptr_len; - bool safety_check_on; -}; - -struct Stage1AirInstElemPtr { - Stage1AirInst base; - - Stage1AirInst *array_ptr; - Stage1AirInst *elem_index; - bool safety_check_on; -}; - -struct Stage1ZirInstVarPtr { - Stage1ZirInst base; - - ZigVar *var; - ScopeFnDef *crossed_fndef_scope; -}; - -struct Stage1AirInstVarPtr { - Stage1AirInst base; - - ZigVar *var; -}; - -// For functions that have a return type for which handle_is_ptr is true, a -// result location pointer is the secret first parameter ("sret"). This -// instruction returns that pointer. -struct Stage1AirInstReturnPtr { - Stage1AirInst base; -}; - -struct Stage1ZirInstCall { - Stage1ZirInst base; - - Stage1ZirInst *fn_ref; - ZigFn *fn_entry; - size_t arg_count; - Stage1ZirInst **args; - Stage1ZirInst *ret_ptr; - ResultLoc *result_loc; - - Stage1ZirInst *new_stack; - - CallModifier modifier; - bool is_async_call_builtin; -}; - -// This is a pass1 instruction, used by @call when the args node is -// a tuple or struct literal. -struct Stage1ZirInstCallArgs { - Stage1ZirInst base; - - Stage1ZirInst *options; - Stage1ZirInst *fn_ref; - Stage1ZirInst **args_ptr; - size_t args_len; - ResultLoc *result_loc; -}; - -// This is a pass1 instruction, used by @call, when the args node -// is not a literal. -// `args` is expected to be either a struct or a tuple. -struct Stage1ZirInstCallExtra { - Stage1ZirInst base; - - Stage1ZirInst *options; - Stage1ZirInst *fn_ref; - Stage1ZirInst *args; - ResultLoc *result_loc; -}; - -// This is a pass1 instruction, used by @asyncCall, when the args node -// is not a literal. -// `args` is expected to be either a struct or a tuple. -struct Stage1ZirInstAsyncCallExtra { - Stage1ZirInst base; - - CallModifier modifier; - Stage1ZirInst *fn_ref; - Stage1ZirInst *ret_ptr; - Stage1ZirInst *new_stack; - Stage1ZirInst *args; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCall { - Stage1AirInst base; - - Stage1AirInst *fn_ref; - ZigFn *fn_entry; - size_t arg_count; - Stage1AirInst **args; - Stage1AirInst *result_loc; - Stage1AirInst *frame_result_loc; - Stage1AirInst *new_stack; - - CallModifier modifier; - - bool is_async_call_builtin; -}; - -struct Stage1ZirInstConst { - Stage1ZirInst base; - - ZigValue *value; -}; - -struct Stage1AirInstConst { - Stage1AirInst base; -}; - -struct Stage1ZirInstReturn { - Stage1ZirInst base; - - Stage1ZirInst *operand; -}; - -// When an IrExecutable is not in a function, a return instruction means that -// the expression returns with that value, even though a return statement from -// an AST perspective is invalid. -struct Stage1AirInstReturn { - Stage1AirInst base; - - Stage1AirInst *operand; -}; - -enum CastOp { - CastOpNoCast, // signifies the function call expression is not a cast - CastOpNoop, // fn call expr is a cast, but does nothing - CastOpIntToFloat, - CastOpFloatToInt, - CastOpBoolToInt, - CastOpNumLitToConcrete, - CastOpErrSet, - CastOpBitCast, -}; - -// TODO get rid of this instruction, replace with instructions for each op code -struct Stage1AirInstCast { - Stage1AirInst base; - - Stage1AirInst *value; - CastOp cast_op; -}; - -struct Stage1ZirInstContainerInitList { - Stage1ZirInst base; - - Stage1ZirInst *elem_type; - size_t item_count; - Stage1ZirInst **elem_result_loc_list; - Stage1ZirInst *result_loc; - AstNode *init_array_type_source_node; -}; - -struct Stage1ZirInstContainerInitFieldsField { - Buf *name; - AstNode *source_node; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstContainerInitFields { - Stage1ZirInst base; - - size_t field_count; - Stage1ZirInstContainerInitFieldsField *fields; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstUnreachable { - Stage1ZirInst base; -}; - -struct Stage1AirInstUnreachable { - Stage1AirInst base; -}; - -struct Stage1ZirInstTypeOf { - Stage1ZirInst base; - - union { - Stage1ZirInst *scalar; // value_count == 1 - Stage1ZirInst **list; // value_count > 1 - } value; - size_t value_count; -}; - -struct Stage1ZirInstSetCold { - Stage1ZirInst base; - - Stage1ZirInst *is_cold; -}; - -struct Stage1ZirInstSetRuntimeSafety { - Stage1ZirInst base; - - Stage1ZirInst *safety_on; -}; - -struct Stage1ZirInstSetFloatMode { - Stage1ZirInst base; - - Stage1ZirInst *scope_value; - Stage1ZirInst *mode_value; -}; - -struct Stage1ZirInstArrayType { - Stage1ZirInst base; - - Stage1ZirInst *size; - Stage1ZirInst *sentinel; - Stage1ZirInst *child_type; -}; - -struct Stage1ZirInstPtrTypeSimple { - Stage1ZirInst base; - - Stage1ZirInst *child_type; -}; - -struct Stage1ZirInstPtrType { - Stage1ZirInst base; - - Stage1ZirInst *sentinel; - Stage1ZirInst *align_value; - Stage1ZirInst *child_type; - uint32_t bit_offset_start; - uint32_t host_int_bytes; - PtrLen ptr_len; - bool is_const; - bool is_volatile; - bool is_allow_zero; -}; - -struct Stage1ZirInstAnyFrameType { - Stage1ZirInst base; - - Stage1ZirInst *payload_type; -}; - -struct Stage1ZirInstSliceType { - Stage1ZirInst base; - - Stage1ZirInst *sentinel; - Stage1ZirInst *align_value; - Stage1ZirInst *child_type; - bool is_const; - bool is_volatile; - bool is_allow_zero; -}; - -struct Stage1ZirInstAsm { - Stage1ZirInst base; - - Stage1ZirInst *asm_template; - Stage1ZirInst **input_list; - Stage1ZirInst **output_types; - ZigVar **output_vars; - size_t return_count; - bool has_side_effects; - bool is_global; -}; - -struct Stage1AirInstAsm { - Stage1AirInst base; - - Buf *asm_template; - AsmToken *token_list; - size_t token_list_len; - Stage1AirInst **input_list; - Stage1AirInst **output_types; - ZigVar **output_vars; - size_t return_count; - bool has_side_effects; -}; - -struct Stage1ZirInstSizeOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - bool bit_size; -}; - -// returns true if nonnull, returns false if null -struct Stage1ZirInstTestNonNull { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstTestNonNull { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -// Takes a pointer to an optional value, returns a pointer -// to the payload. -struct Stage1ZirInstOptionalUnwrapPtr { - Stage1ZirInst base; - - Stage1ZirInst *base_ptr; - bool safety_check_on; -}; - -struct Stage1AirInstOptionalUnwrapPtr { - Stage1AirInst base; - - Stage1AirInst *base_ptr; - bool safety_check_on; - bool initializing; -}; - -struct Stage1ZirInstCtz { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstCtz { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstClz { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstClz { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstPopCount { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstPopCount { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1AirInstUnionTag { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstImport { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstRef { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstRef { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstCompileErr { - Stage1ZirInst base; - - Stage1ZirInst *msg; -}; - -struct Stage1ZirInstCompileLog { - Stage1ZirInst base; - - size_t msg_count; - Stage1ZirInst **msg_list; -}; - -struct Stage1ZirInstErrName { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstErrName { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstCImport { - Stage1ZirInst base; -}; - -struct Stage1ZirInstCInclude { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstCDefine { - Stage1ZirInst base; - - Stage1ZirInst *name; - Stage1ZirInst *value; -}; - -struct Stage1ZirInstCUndef { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstEmbedFile { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstCmpxchg { - Stage1ZirInst base; - - bool is_weak; - Stage1ZirInst *type_value; - Stage1ZirInst *ptr; - Stage1ZirInst *cmp_value; - Stage1ZirInst *new_value; - Stage1ZirInst *success_order_value; - Stage1ZirInst *failure_order_value; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCmpxchg { - Stage1AirInst base; - - AtomicOrder success_order; - AtomicOrder failure_order; - Stage1AirInst *ptr; - Stage1AirInst *cmp_value; - Stage1AirInst *new_value; - Stage1AirInst *result_loc; - bool is_weak; -}; - -struct Stage1ZirInstFence { - Stage1ZirInst base; - - Stage1ZirInst *order; -}; - -struct Stage1AirInstFence { - Stage1AirInst base; - - AtomicOrder order; -}; - -struct Stage1ZirInstReduce { - Stage1ZirInst base; - - Stage1ZirInst *op; - Stage1ZirInst *value; -}; - -struct Stage1AirInstReduce { - Stage1AirInst base; - - ReduceOp op; - Stage1AirInst *value; -}; - -struct Stage1ZirInstTruncate { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstTruncate { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstFloatCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstErrSetCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstIntToFloat { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstFloatToInt { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstBoolToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1ZirInstVectorType { - Stage1ZirInst base; - - Stage1ZirInst *len; - Stage1ZirInst *elem_type; -}; - -struct Stage1ZirInstBoolNot { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstBoolNot { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstMemset { - Stage1ZirInst base; - - Stage1ZirInst *dest_ptr; - Stage1ZirInst *byte; - Stage1ZirInst *count; -}; - -struct Stage1AirInstMemset { - Stage1AirInst base; - - Stage1AirInst *dest_ptr; - Stage1AirInst *byte; - Stage1AirInst *count; -}; - -struct Stage1ZirInstMemcpy { - Stage1ZirInst base; - - Stage1ZirInst *dest_ptr; - Stage1ZirInst *src_ptr; - Stage1ZirInst *count; -}; - -struct Stage1AirInstMemcpy { - Stage1AirInst base; - - Stage1AirInst *dest_ptr; - Stage1AirInst *src_ptr; - Stage1AirInst *count; -}; - -struct Stage1ZirInstWasmMemorySize { - Stage1ZirInst base; - - Stage1ZirInst *index; -}; - -struct Stage1AirInstWasmMemorySize { - Stage1AirInst base; - - Stage1AirInst *index; -}; - -struct Stage1ZirInstWasmMemoryGrow { - Stage1ZirInst base; - - Stage1ZirInst *index; - Stage1ZirInst *delta; -}; - -struct Stage1AirInstWasmMemoryGrow { - Stage1AirInst base; - - Stage1AirInst *index; - Stage1AirInst *delta; -}; - -struct Stage1ZirInstSrc { - Stage1ZirInst base; -}; - -struct Stage1ZirInstPrefetch { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *options; -}; - -struct Stage1AirInstPrefetch { - Stage1AirInst base; - - Stage1AirInst *ptr; - PrefetchRw rw; - // Must be in the range 0-3 inclusive - uint8_t locality; - PrefetchCache cache; -}; - - -struct Stage1ZirInstSlice { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *start; - Stage1ZirInst *end; - Stage1ZirInst *sentinel; - ResultLoc *result_loc; - bool safety_check_on; -}; - -struct Stage1AirInstSlice { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *start; - Stage1AirInst *end; - Stage1AirInst *result_loc; - ZigValue *sentinel; - bool safety_check_on; -}; - -struct Stage1ZirInstBreakpoint { - Stage1ZirInst base; -}; - -struct Stage1AirInstBreakpoint { - Stage1AirInst base; -}; - -struct Stage1ZirInstReturnAddress { - Stage1ZirInst base; -}; - -struct Stage1AirInstReturnAddress { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameAddress { - Stage1ZirInst base; -}; - -struct Stage1AirInstFrameAddress { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameHandle { - Stage1ZirInst base; -}; - -struct Stage1AirInstFrameHandle { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameType { - Stage1ZirInst base; - - Stage1ZirInst *fn; -}; - -struct Stage1ZirInstFrameSize { - Stage1ZirInst base; - - Stage1ZirInst *fn; -}; - -struct Stage1AirInstFrameSize { - Stage1AirInst base; - - Stage1AirInst *fn; -}; - -enum IrOverflowOp { - IrOverflowOpAdd, - IrOverflowOpSub, - IrOverflowOpMul, - IrOverflowOpShl, -}; - -struct Stage1ZirInstOverflowOp { - Stage1ZirInst base; - - IrOverflowOp op; - Stage1ZirInst *type_value; - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Stage1ZirInst *result_ptr; -}; - -struct Stage1AirInstOverflowOp { - Stage1AirInst base; - - IrOverflowOp op; - Stage1AirInst *op1; - Stage1AirInst *op2; - Stage1AirInst *result_ptr; - - // TODO can this field be removed? - ZigType *result_ptr_type; -}; - -struct Stage1ZirInstMulAdd { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Stage1ZirInst *op3; -}; - -struct Stage1AirInstMulAdd { - Stage1AirInst base; - - Stage1AirInst *op1; - Stage1AirInst *op2; - Stage1AirInst *op3; -}; - -struct Stage1ZirInstAlignOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -// returns true if error, returns false if not error -struct Stage1ZirInstTestErr { - Stage1ZirInst base; - - Stage1ZirInst *base_ptr; - bool resolve_err_set; - bool base_ptr_is_payload; -}; - -struct Stage1AirInstTestErr { - Stage1AirInst base; - - Stage1AirInst *err_union; -}; - -// Takes an error union pointer, returns a pointer to the error code. -struct Stage1ZirInstUnwrapErrCode { - Stage1ZirInst base; - - Stage1ZirInst *err_union_ptr; - bool initializing; -}; - -struct Stage1AirInstUnwrapErrCode { - Stage1AirInst base; - - Stage1AirInst *err_union_ptr; - bool initializing; -}; - -struct Stage1ZirInstUnwrapErrPayload { - Stage1ZirInst base; - - Stage1ZirInst *value; - bool safety_check_on; - bool initializing; -}; - -struct Stage1AirInstUnwrapErrPayload { - Stage1AirInst base; - - Stage1AirInst *value; - bool safety_check_on; - bool initializing; -}; - -struct Stage1AirInstOptionalWrap { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1AirInstErrWrapPayload { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1AirInstErrWrapCode { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstFnProto { - Stage1ZirInst base; - - Stage1ZirInst **param_types; - Stage1ZirInst *align_value; - Stage1ZirInst *callconv_value; - Stage1ZirInst *return_type; - bool is_var_args; -}; - -// true if the target value is compile time known, false otherwise -struct Stage1ZirInstTestComptime { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1ZirInstPtrCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *ptr; - bool safety_check_on; -}; - -struct Stage1AirInstPtrCast { - Stage1AirInst base; - - Stage1AirInst *ptr; - bool safety_check_on; -}; - -struct Stage1ZirInstImplicitCast { - Stage1ZirInst base; - - Stage1ZirInst *operand; - ResultLocCast *result_loc_cast; -}; - -struct Stage1ZirInstBitCast { - Stage1ZirInst base; - - Stage1ZirInst *operand; - ResultLocBitCast *result_loc_bit_cast; -}; - -struct Stage1AirInstBitCast { - Stage1AirInst base; - - Stage1AirInst *operand; -}; - -struct Stage1AirInstWidenOrShorten { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstPtrToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstPtrToInt { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntToPtr { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToPtr { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntToEnum { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToEnum { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstEnumToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1ZirInstIntToErr { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToErr { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstErrToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstErrToInt { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstCheckSwitchProngsRange { - Stage1ZirInst *start; - Stage1ZirInst *end; -}; - -struct Stage1ZirInstCheckSwitchProngs { - Stage1ZirInst base; - - Stage1ZirInst *target_value; - Stage1ZirInstCheckSwitchProngsRange *ranges; - size_t range_count; - AstNode* else_prong; -}; - -struct Stage1ZirInstCheckStatementIsVoid { - Stage1ZirInst base; - - Stage1ZirInst *statement_value; -}; - -struct Stage1ZirInstTypeName { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -struct Stage1ZirInstDeclRef { - Stage1ZirInst base; - - LVal lval; - Tld *tld; -}; - -struct Stage1ZirInstPanic { - Stage1ZirInst base; - - Stage1ZirInst *msg; -}; - -struct Stage1AirInstPanic { - Stage1AirInst base; - - Stage1AirInst *msg; -}; - -struct Stage1ZirInstTagName { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstTagName { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstFieldParentPtr { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; - Stage1ZirInst *field_ptr; -}; - -struct Stage1AirInstFieldParentPtr { - Stage1AirInst base; - - Stage1AirInst *field_ptr; - TypeStructField *field; -}; - -struct Stage1ZirInstOffsetOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstBitOffsetOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstTypeInfo { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -struct Stage1ZirInstType { - Stage1ZirInst base; - - Stage1ZirInst *type_info; -}; - -struct Stage1ZirInstHasField { - Stage1ZirInst base; - - Stage1ZirInst *container_type; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstSetEvalBranchQuota { - Stage1ZirInst base; - - Stage1ZirInst *new_quota; -}; - -struct Stage1ZirInstAlignCast { - Stage1ZirInst base; - - Stage1ZirInst *align_bytes; - Stage1ZirInst *target; -}; - -struct Stage1AirInstAlignCast { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstAddrSpaceCast { - Stage1ZirInst base; - - Stage1ZirInst *addrspace; - Stage1ZirInst *ptr; -}; - -struct Stage1ZirInstSetAlignStack { - Stage1ZirInst base; - - Stage1ZirInst *align_bytes; -}; - -struct Stage1ZirInstArgType { - Stage1ZirInst base; - - Stage1ZirInst *fn_type; - Stage1ZirInst *arg_index; -}; - -struct Stage1ZirInstExport { - Stage1ZirInst base; - - Stage1ZirInst *target; - Stage1ZirInst *options; -}; - -struct Stage1ZirInstExtern { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *options; -}; - -struct Stage1AirInstExtern { - Stage1AirInst base; - - Buf *name; - GlobalLinkageId linkage; - bool is_thread_local; -}; - -enum IrInstErrorReturnTraceOptional { - IrInstErrorReturnTraceNull, - IrInstErrorReturnTraceNonNull, -}; - -struct Stage1ZirInstErrorReturnTrace { - Stage1ZirInst base; - - IrInstErrorReturnTraceOptional optional; -}; - -struct Stage1AirInstErrorReturnTrace { - Stage1AirInst base; - - IrInstErrorReturnTraceOptional optional; -}; - -struct Stage1ZirInstErrorUnion { - Stage1ZirInst base; - - Stage1ZirInst *err_set; - Stage1ZirInst *payload; - Buf *type_name; -}; - -struct Stage1ZirInstAtomicRmw { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *op; - Stage1ZirInst *operand; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicRmw { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *operand; - AtomicRmwOp op; - AtomicOrder ordering; -}; - -struct Stage1ZirInstAtomicLoad { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicLoad { - Stage1AirInst base; - - Stage1AirInst *ptr; - AtomicOrder ordering; -}; - -struct Stage1ZirInstAtomicStore { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *value; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicStore { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *value; - AtomicOrder ordering; -}; - -struct Stage1ZirInstSaveErrRetAddr { - Stage1ZirInst base; -}; - -struct Stage1AirInstSaveErrRetAddr { - Stage1AirInst base; -}; - -struct Stage1ZirInstAddImplicitReturnType { - Stage1ZirInst base; - - Stage1ZirInst *value; - ResultLocReturn *result_loc_ret; -}; - -// For float ops that take a single argument -struct Stage1ZirInstFloatOp { - Stage1ZirInst base; - - Stage1ZirInst *operand; - BuiltinFnId fn_id; -}; - -struct Stage1AirInstFloatOp { - Stage1AirInst base; - - Stage1AirInst *operand; - BuiltinFnId fn_id; -}; - -struct Stage1ZirInstCheckRuntimeScope { - Stage1ZirInst base; - - Stage1ZirInst *scope_is_comptime; - Stage1ZirInst *is_comptime; -}; - -struct Stage1ZirInstBswap { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstBswap { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstBitReverse { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstBitReverse { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1AirInstArrayToVector { - Stage1AirInst base; - - Stage1AirInst *array; -}; - -struct Stage1AirInstVectorToArray { - Stage1AirInst base; - - Stage1AirInst *vector; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstShuffleVector { - Stage1ZirInst base; - - Stage1ZirInst *scalar_type; - Stage1ZirInst *a; - Stage1ZirInst *b; - Stage1ZirInst *mask; // This is in zig-format, not llvm format -}; - -struct Stage1AirInstShuffleVector { - Stage1AirInst base; - - Stage1AirInst *a; - Stage1AirInst *b; - Stage1AirInst *mask; // This is in zig-format, not llvm format -}; - -struct Stage1ZirInstSelect { - Stage1ZirInst base; - - Stage1ZirInst *scalar_type; - Stage1ZirInst *pred; // This is in zig-format, not llvm format - Stage1ZirInst *a; - Stage1ZirInst *b; -}; - -struct Stage1AirInstSelect { - Stage1AirInst base; - - Stage1AirInst *pred; // This is in zig-format, not llvm format - Stage1AirInst *a; - Stage1AirInst *b; -}; - -struct Stage1ZirInstSplat { - Stage1ZirInst base; - - Stage1ZirInst *len; - Stage1ZirInst *scalar; -}; - -struct Stage1AirInstSplat { - Stage1AirInst base; - - Stage1AirInst *scalar; -}; - -struct Stage1AirInstAssertZero { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1AirInstAssertNonNull { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstUnionInitNamedField { - Stage1ZirInst base; - - Stage1ZirInst *union_type; - Stage1ZirInst *field_name; - Stage1ZirInst *field_result_loc; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstHasDecl { - Stage1ZirInst base; - - Stage1ZirInst *container; - Stage1ZirInst *name; -}; - -struct Stage1ZirInstUndeclaredIdent { - Stage1ZirInst base; - - Buf *name; -}; - -struct Stage1ZirInstAlloca { - Stage1ZirInst base; - - Stage1ZirInst *align; - Stage1ZirInst *is_comptime; - const char *name_hint; -}; - -struct Stage1AirInstAlloca { - Stage1AirInst base; - - uint32_t align; - const char *name_hint; - size_t field_index; -}; - -struct Stage1ZirInstEndExpr { - Stage1ZirInst base; - - Stage1ZirInst *value; - ResultLoc *result_loc; -}; - -// This one is for writing through the result pointer. -struct Stage1ZirInstResolveResult { - Stage1ZirInst base; - - ResultLoc *result_loc; - Stage1ZirInst *ty; -}; - -struct Stage1ZirInstResetResult { - Stage1ZirInst base; - - ResultLoc *result_loc; -}; - -struct Stage1AirInstPtrOfArrayToSlice { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstSuspendBegin { - Stage1ZirInst base; -}; - -struct Stage1AirInstSuspendBegin { - Stage1AirInst base; - - LLVMBasicBlockRef resume_bb; -}; - -struct Stage1ZirInstSuspendFinish { - Stage1ZirInst base; - - Stage1ZirInstSuspendBegin *begin; -}; - -struct Stage1AirInstSuspendFinish { - Stage1AirInst base; - - Stage1AirInstSuspendBegin *begin; -}; - -struct Stage1ZirInstAwait { - Stage1ZirInst base; - - Stage1ZirInst *frame; - ResultLoc *result_loc; - bool is_nosuspend; -}; - -struct Stage1AirInstAwait { - Stage1AirInst base; - - Stage1AirInst *frame; - Stage1AirInst *result_loc; - ZigFn *target_fn; - bool is_nosuspend; -}; - -struct Stage1ZirInstResume { - Stage1ZirInst base; - - Stage1ZirInst *frame; -}; - -struct Stage1AirInstResume { - Stage1AirInst base; - - Stage1AirInst *frame; -}; - -enum SpillId { - SpillIdInvalid, - SpillIdRetErrCode, -}; - -struct Stage1ZirInstSpillBegin { - Stage1ZirInst base; - - Stage1ZirInst *operand; - SpillId spill_id; -}; - -struct Stage1AirInstSpillBegin { - Stage1AirInst base; - - SpillId spill_id; - Stage1AirInst *operand; -}; - -struct Stage1ZirInstSpillEnd { - Stage1ZirInst base; - - Stage1ZirInstSpillBegin *begin; -}; - -struct Stage1AirInstSpillEnd { - Stage1AirInst base; - - Stage1AirInstSpillBegin *begin; -}; - -struct Stage1AirInstVectorExtractElem { - Stage1AirInst base; - - Stage1AirInst *vector; - Stage1AirInst *index; -}; - -enum ResultLocId { - ResultLocIdInvalid, - ResultLocIdNone, - ResultLocIdVar, - ResultLocIdReturn, - ResultLocIdPeer, - ResultLocIdPeerParent, - ResultLocIdInstruction, - ResultLocIdBitCast, - ResultLocIdCast, -}; - -// Additions to this struct may need to be handled in -// ir_reset_result -struct ResultLoc { - ResultLocId id; - bool written; - bool allow_write_through_const; - Stage1AirInst *resolved_loc; // result ptr - Stage1ZirInst *source_instruction; - Stage1AirInst *gen_instruction; // value to store to the result loc - ZigType *implicit_elem_type; -}; - -struct ResultLocNone { - ResultLoc base; -}; - -struct ResultLocVar { - ResultLoc base; - - ZigVar *var; -}; - -struct ResultLocReturn { - ResultLoc base; - - bool implicit_return_type_done; -}; - -struct IrSuspendPosition { - size_t basic_block_index; - size_t instruction_index; -}; - -struct ResultLocPeerParent { - ResultLoc base; - - bool skipped; - bool done_resuming; - Stage1ZirBasicBlock *end_bb; - ResultLoc *parent; - ZigList peers; - ZigType *resolved_type; - Stage1ZirInst *is_comptime; -}; - -struct ResultLocPeer { - ResultLoc base; - - ResultLocPeerParent *parent; - Stage1ZirBasicBlock *next_bb; - IrSuspendPosition suspend_pos; -}; - -// The result location is the source instruction -struct ResultLocInstruction { - ResultLoc base; -}; - -// The source_instruction is the destination type -struct ResultLocBitCast { - ResultLoc base; - - ResultLoc *parent; -}; - -// The source_instruction is the destination type -struct ResultLocCast { - ResultLoc base; - - ResultLoc *parent; -}; - -static const size_t slice_ptr_index = 0; -static const size_t slice_len_index = 1; - -static const size_t maybe_child_index = 0; -static const size_t maybe_null_index = 1; - -static const size_t err_union_payload_index = 0; -static const size_t err_union_err_index = 1; - -// label (grep this): [fn_frame_struct_layout] -static const size_t frame_fn_ptr_index = 0; -static const size_t frame_resume_index = 1; -static const size_t frame_awaiter_index = 2; -static const size_t frame_ret_start = 3; - -// TODO https://github.com/ziglang/zig/issues/3056 -// We require this to be a power of 2 so that we can use shifting rather than -// remainder division. -static const size_t stack_trace_ptr_count = 32; // Must be a power of 2. - -#define NAMESPACE_SEP_CHAR '.' -#define NAMESPACE_SEP_STR "." - -#define CACHE_OUT_SUBDIR "o" -#define CACHE_HASH_SUBDIR "h" - -enum FloatMode { - FloatModeStrict, - FloatModeOptimized, -}; - -enum FnWalkId { - FnWalkIdAttrs, - FnWalkIdCall, - FnWalkIdTypes, - FnWalkIdVars, - FnWalkIdInits, -}; - -struct FnWalkAttrs { - ZigFn *fn; - LLVMValueRef llvm_fn; - unsigned gen_i; -}; - -struct FnWalkCall { - ZigList *gen_param_values; - ZigList *gen_param_types; - Stage1AirInstCall *inst; - bool is_var_args; -}; - -struct FnWalkTypes { - ZigList *param_di_types; - ZigList *gen_param_types; -}; - -struct FnWalkVars { - ZigType *import; - LLVMValueRef llvm_fn; - ZigFn *fn; - ZigVar *var; - unsigned gen_i; -}; - -struct FnWalkInits { - LLVMValueRef llvm_fn; - ZigFn *fn; - unsigned gen_i; -}; - -struct FnWalk { - FnWalkId id; - union { - FnWalkAttrs attrs; - FnWalkCall call; - FnWalkTypes types; - FnWalkVars vars; - FnWalkInits inits; - } data; -}; - -#endif diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp deleted file mode 100644 index 0f8428d1b4a2..000000000000 --- a/src/stage1/analyze.cpp +++ /dev/null @@ -1,10443 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "analyze.hpp" -#include "codegen.hpp" -#include "error.hpp" -#include "astgen.hpp" -#include "ir.hpp" -#include "ir_print.hpp" -#include "os.hpp" -#include "parser.hpp" -#include "softfloat.hpp" -#include "zig_llvm.h" - - -static const size_t default_backward_branch_quota = 1000; - -static Error ATTRIBUTE_MUST_USE resolve_struct_type(CodeGen *g, ZigType *struct_type); - -static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); -static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); -static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type); -static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type); -static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type); -static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); -static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status); -static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); -static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); -static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame); - -// nullptr means not analyzed yet; this one means currently being analyzed -static const AstNode *inferred_async_checking = reinterpret_cast(0x1); -// this one means analyzed and it's not async -static const AstNode *inferred_async_none = reinterpret_cast(0x2); - -static bool is_top_level_struct(ZigType *import) { - return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr; -} - -static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, - TokenIndex token, Buf *msg) -{ - assert(is_top_level_struct(owner)); - RootStruct *root_struct = owner->data.structure.root_struct; - uint32_t byte_offset = root_struct->token_locs[token].offset; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, - buf_ptr(root_struct->source_code), msg); - - err_msg_add_note(parent_msg, err); - return err; -} - -ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, - uint32_t bad_index) -{ - assert(is_top_level_struct(owner)); - RootStruct *root_struct = owner->data.structure.root_struct; - uint32_t byte_offset = root_struct->token_locs[token].offset + bad_index; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, - buf_ptr(root_struct->source_code), msg); - - g->errors.append(err); - g->trace_err = err; - return err; -} - -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg) { - return add_token_error_offset(g, owner, token, msg, 0); -} - -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - return add_token_error(g, node->owner, node->main_token, msg); -} - -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) { - return add_error_note_token(g, parent_msg, node->owner, node->main_token, msg); -} - -ZigType *new_type_table_entry(ZigTypeId id) { - ZigType *entry = heap::c_allocator.create(); - entry->id = id; - return entry; -} - -static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdStruct: - return &type_entry->data.structure.decls_scope; - case ZigTypeIdEnum: - return &type_entry->data.enumeration.decls_scope; - case ZigTypeIdUnion: - return &type_entry->data.unionation.decls_scope; - case ZigTypeIdOpaque: - return &type_entry->data.opaque.decls_scope; - default: - zig_unreachable(); - } -} - -static ScopeExpr *find_expr_scope(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdExpr: - return reinterpret_cast(scope); - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdDecls: - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdVarDecl: - case ScopeIdCImport: - case ScopeIdSuspend: - case ScopeIdTypeOf: - case ScopeIdBlock: - return nullptr; - case ScopeIdLoop: - case ScopeIdRuntime: - scope = scope->parent; - continue; - } - } -} - -static void update_progress_display(CodeGen *g) { - stage2_progress_update_node(g->sub_progress_node, - g->resolve_queue_index + g->fn_defs_index, - g->resolve_queue.length + g->fn_defs.length); -} - -ScopeDecls *get_container_scope(ZigType *type_entry) { - return *get_container_scope_ptr(type_entry); -} - -void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) { - dest->codegen = g; - dest->id = id; - dest->source_node = source_node; - dest->parent = parent; -} - -ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, - ZigType *import, Buf *bare_name) -{ - ScopeDecls *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDecls, node, parent); - scope->decl_table.init(4); - scope->container_type = container_type; - scope->import = import; - scope->bare_name = bare_name; - return scope; -} - -ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeBlock); - ScopeBlock *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdBlock, node, parent); - scope->name = node->data.block.name; - return scope; -} - -ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeDefer); - ScopeDefer *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDefer, node, parent); - return scope; -} - -ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeDefer); - ScopeDeferExpr *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDeferExpr, node, parent); - return scope; -} - -Scope *create_var_scope(CodeGen *g, AstNode *node, Scope *parent, ZigVar *var) { - ScopeVarDecl *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdVarDecl, node, parent); - scope->var = var; - return &scope->base; -} - -ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeFnCallExpr); - ScopeCImport *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdCImport, node, parent); - buf_resize(&scope->buf, 0); - return scope; -} - -ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeLoop *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdLoop, node, parent); - if (node->type == NodeTypeWhileExpr) { - scope->name = node->data.while_expr.name; - } else if (node->type == NodeTypeForExpr) { - scope->name = node->data.for_expr.name; - } else { - zig_unreachable(); - } - return scope; -} - -Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, Stage1ZirInst *is_comptime) { - ScopeRuntime *scope = heap::c_allocator.create(); - scope->is_comptime = is_comptime; - init_scope(g, &scope->base, ScopeIdRuntime, node, parent); - return &scope->base; -} - -ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeSuspend); - ScopeSuspend *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdSuspend, node, parent); - return scope; -} - -ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry) { - ScopeFnDef *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdFnDef, node, parent); - scope->fn_entry = fn_entry; - return scope; -} - -Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeCompTime *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdCompTime, node, parent); - return &scope->base; -} - -Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeNoSuspend *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdNoSuspend, node, parent); - return &scope->base; -} - -Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeTypeOf *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdTypeOf, node, parent); - return &scope->base; -} - -ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeExpr *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdExpr, node, parent); - ScopeExpr *parent_expr = find_expr_scope(parent); - if (parent_expr != nullptr) { - size_t new_len = parent_expr->children_len + 1; - parent_expr->children_ptr = heap::c_allocator.reallocate_nonzero( - parent_expr->children_ptr, parent_expr->children_len, new_len); - parent_expr->children_ptr[parent_expr->children_len] = scope; - parent_expr->children_len = new_len; - } - return scope; -} - -ZigType *get_scope_import(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - assert(is_top_level_struct(decls_scope->import)); - return decls_scope->import; - } - scope = scope->parent; - } - zig_unreachable(); -} - -ScopeTypeOf *get_scope_typeof(Scope *scope) { - while (scope) { - switch (scope->id) { - case ScopeIdTypeOf: - return reinterpret_cast(scope); - case ScopeIdFnDef: - case ScopeIdDecls: - return nullptr; - default: - scope = scope->parent; - continue; - } - } - zig_unreachable(); -} - -static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope, - Buf *bare_name) -{ - ZigType *entry = new_type_table_entry(id); - *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry, - get_scope_import(parent_scope), bare_name); - return entry; -} - -static uint8_t bits_needed_for_unsigned(uint64_t x) { - if (x == 0) { - return 0; - } - uint8_t base = log2_u64(x); - uint64_t upper = (((uint64_t)1) << base) - 1; - return (upper >= x) ? base : (base + 1); -} - -AstNode *type_decl_node(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.decl_node; - case ZigTypeIdEnum: - return type_entry->data.enumeration.decl_node; - case ZigTypeIdUnion: - return type_entry->data.unionation.decl_node; - case ZigTypeIdFnFrame: - return type_entry->data.frame.fn->proto_node; - case ZigTypeIdOpaque: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return nullptr; - } - zig_unreachable(); -} - -bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.resolve_status >= status; - case ZigTypeIdUnion: - return type_entry->data.unionation.resolve_status >= status; - case ZigTypeIdEnum: - return type_entry->data.enumeration.resolve_status >= status; - case ZigTypeIdFnFrame: - switch (status) { - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusUnstarted: - case ResolveStatusZeroBitsKnown: - return true; - case ResolveStatusAlignmentKnown: - case ResolveStatusSizeKnown: - return type_entry->data.frame.locals_struct != nullptr; - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - return type_entry->llvm_type != nullptr; - } - zig_unreachable(); - case ZigTypeIdOpaque: - return status < ResolveStatusSizeKnown; - case ZigTypeIdPointer: - switch (status) { - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusUnstarted: - return true; - case ResolveStatusZeroBitsKnown: - case ResolveStatusAlignmentKnown: - case ResolveStatusSizeKnown: - return type_entry->abi_size != SIZE_MAX; - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - return type_entry->llvm_type != nullptr; - } - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return true; - } - zig_unreachable(); -} - -bool type_is_complete(ZigType *type_entry) { - return type_is_resolved(type_entry, ResolveStatusSizeKnown); -} - -uint64_t type_size(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusSizeKnown)); - return type_entry->abi_size; -} - -uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusSizeKnown)); - return type_entry->size_in_bits; -} - -uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown)); - return type_entry->abi_align; -} - -static bool is_slice(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; -} - -ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { - return get_int_type(g, false, bits_needed_for_unsigned(x)); -} - -ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) { - if (result_type != nullptr && result_type->any_frame_parent != nullptr) { - return result_type->any_frame_parent; - } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) { - return g->builtin_types.entry_any_frame; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame); - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - entry->data.any_frame.result_type = result_type; - buf_init_from_str(&entry->name, "anyframe"); - if (result_type != nullptr) { - buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name)); - } - - if (result_type != nullptr) { - result_type->any_frame_parent = entry; - } else if (result_type == nullptr) { - g->builtin_types.entry_any_frame = entry; - } - return entry; -} - -ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { - if (fn->frame_type != nullptr) { - return fn->frame_type; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdFnFrame); - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "@Frame(%s)", buf_ptr(&fn->symbol_name)); - - entry->data.frame.fn = fn; - - // Async function frames are always non-zero bits because they always have a resume index. - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - - fn->frame_type = entry; - return entry; -} - -static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) { - const char *const_str = ptr_type->data.pointer.is_const ? "const " : ""; - const char *volatile_str = ptr_type->data.pointer.is_volatile ? "volatile " : ""; - const char *allow_zero_str; - if (ptr_type->data.pointer.ptr_len == PtrLenC) { - assert(ptr_type->data.pointer.allow_zero); - allow_zero_str = ""; - } else { - allow_zero_str = ptr_type->data.pointer.allow_zero ? "allowzero " : ""; - } - if (ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.host_int_bytes != 0 || - ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) - { - buf_appendf(type_name, "align("); - if (ptr_type->data.pointer.explicit_alignment != 0) { - buf_appendf(type_name, "%" PRIu32, ptr_type->data.pointer.explicit_alignment); - } - if (ptr_type->data.pointer.host_int_bytes != 0) { - buf_appendf(type_name, ":%" PRIu32 ":%" PRIu32, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes); - } - if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - buf_appendf(type_name, ":?"); - } else if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - buf_appendf(type_name, ":%" PRIu32, ptr_type->data.pointer.vector_index); - } - buf_appendf(type_name, ") "); - } - buf_appendf(type_name, "%s%s%s", const_str, volatile_str, allow_zero_str); - if (ptr_type->data.pointer.inferred_struct_field != nullptr) { - buf_appendf(type_name, " field '%s' of %s)", - buf_ptr(ptr_type->data.pointer.inferred_struct_field->field_name), - buf_ptr(&ptr_type->data.pointer.inferred_struct_field->inferred_struct_type->name)); - } else { - buf_appendf(type_name, "%s", buf_ptr(&ptr_type->data.pointer.child_type->name)); - } -} - -ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, - uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, - uint32_t vector_index, InferredStructField *inferred_struct_field, ZigValue *sentinel) -{ - assert(ptr_len != PtrLenC || allow_zero); - assert(!type_is_invalid(child_type)); - assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); - - if (byte_alignment != 0) { - uint32_t abi_alignment = get_abi_alignment(g, child_type); - if (byte_alignment == abi_alignment) - byte_alignment = 0; - } - - if (host_int_bytes != 0 && vector_index == VECTOR_INDEX_NONE) { - uint32_t child_type_bits = type_size_bits(g, child_type); - if (host_int_bytes * 8 == child_type_bits) { - assert(bit_offset_in_host == 0); - host_int_bytes = 0; - } - } - - TypeId type_id = {}; - ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || - allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr || - sentinel != nullptr) - { - type_id.id = ZigTypeIdPointer; - type_id.data.pointer.codegen = g; - type_id.data.pointer.child_type = child_type; - type_id.data.pointer.is_const = is_const; - type_id.data.pointer.is_volatile = is_volatile; - type_id.data.pointer.alignment = byte_alignment; - type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; - type_id.data.pointer.host_int_bytes = host_int_bytes; - type_id.data.pointer.ptr_len = ptr_len; - type_id.data.pointer.allow_zero = allow_zero; - type_id.data.pointer.vector_index = vector_index; - type_id.data.pointer.inferred_struct_field = inferred_struct_field; - type_id.data.pointer.sentinel = sentinel; - - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) - return existing_entry->value; - } else { - assert(bit_offset_in_host == 0); - parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; - if (*parent_pointer) { - assert((*parent_pointer)->data.pointer.explicit_alignment == 0); - return *parent_pointer; - } - } - - ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - - buf_resize(&entry->name, 0); - if (inferred_struct_field != nullptr) { - buf_appendf(&entry->name, "("); - } - switch (ptr_len) { - case PtrLenSingle: - assert(sentinel == nullptr); - buf_appendf(&entry->name, "*"); - break; - case PtrLenUnknown: - buf_appendf(&entry->name, "[*"); - break; - case PtrLenC: - assert(sentinel == nullptr); - buf_appendf(&entry->name, "[*c]"); - break; - } - if (sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); - } - switch (ptr_len) { - case PtrLenSingle: - case PtrLenC: - break; - case PtrLenUnknown: - buf_appendf(&entry->name, "]"); - break; - } - - if (inferred_struct_field != nullptr) { - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = UINT32_MAX; - } else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { - if (type_has_bits(g, child_type)) { - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - } else { - assert(byte_alignment == 0); - entry->abi_size = 0; - entry->size_in_bits = 0; - entry->abi_align = 0; - } - } else { - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = UINT32_MAX; - } - - entry->data.pointer.ptr_len = ptr_len; - entry->data.pointer.child_type = child_type; - entry->data.pointer.is_const = is_const; - entry->data.pointer.is_volatile = is_volatile; - entry->data.pointer.explicit_alignment = byte_alignment; - entry->data.pointer.bit_offset_in_host = bit_offset_in_host; - entry->data.pointer.host_int_bytes = host_int_bytes; - entry->data.pointer.allow_zero = allow_zero; - entry->data.pointer.vector_index = vector_index; - entry->data.pointer.inferred_struct_field = inferred_struct_field; - entry->data.pointer.sentinel = sentinel; - - append_ptr_type_attrs(&entry->name, entry); - - if (parent_pointer) { - *parent_pointer = entry; - } else { - g->type_table.put(type_id, entry); - } - return entry; -} - -ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, - uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) -{ - return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, - byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr, nullptr); -} - -ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { - return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, nullptr); -} - -ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { - ZigType *result = get_optional_type2(g, child_type); - if (result == nullptr) { - codegen_report_errors_and_exit(g); - } - return result; -} - -ZigType *get_optional_type2(CodeGen *g, ZigType *child_type) { - if (child_type->optional_parent != nullptr) { - return child_type->optional_parent; - } - - Error err; - if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - return nullptr; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdOptional); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); - - if (!type_has_bits(g, child_type)) { - entry->size_in_bits = g->builtin_types.entry_bool->size_in_bits; - entry->abi_size = g->builtin_types.entry_bool->abi_size; - entry->abi_align = g->builtin_types.entry_bool->abi_align; - } else if (type_is_nonnull_ptr(g, child_type) || child_type->id == ZigTypeIdErrorSet) { - // This is an optimization but also is necessary for calling C - // functions where all pointers are optional pointers. - // Function types are technically pointers. - entry->size_in_bits = child_type->size_in_bits; - entry->abi_size = child_type->abi_size; - entry->abi_align = child_type->abi_align; - } else { - // This value only matters if the type is legal in a packed struct, which is not - // true for optional types which did not fit the above 2 categories (zero bit child type, - // or nonnull ptr child type, or error set child type). - entry->size_in_bits = child_type->size_in_bits + 1; - - // We're going to make a struct with the child type as the first field, - // and a bool as the second. Since the child type's abi alignment is guaranteed - // to be >= the bool's abi size (1 byte), the added size is exactly equal to the - // child type's ABI alignment. - assert(child_type->abi_align >= g->builtin_types.entry_bool->abi_size); - entry->abi_align = child_type->abi_align; - entry->abi_size = child_type->abi_size + child_type->abi_align; - } - - entry->data.maybe.child_type = child_type; - entry->data.maybe.resolve_status = ResolveStatusSizeKnown; - - child_type->optional_parent = entry; - return entry; -} - -static size_t align_forward(size_t addr, size_t alignment) { - return (addr + alignment - 1) & ~(alignment - 1); -} - -static size_t next_field_offset(size_t offset, size_t align_from_zero, size_t field_size, size_t next_field_align) { - // Convert offset to a pretend address which has the specified alignment. - size_t addr = offset + align_from_zero; - // March the address forward to respect the field alignment. - size_t aligned_addr = align_forward(addr + field_size, next_field_align); - // Convert back from pretend address to offset. - return aligned_addr - align_from_zero; -} - -ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type) { - assert(err_set_type->id == ZigTypeIdErrorSet); - assert(!type_is_invalid(payload_type)); - - TypeId type_id = {}; - type_id.id = ZigTypeIdErrorUnion; - type_id.data.error_union.err_set_type = err_set_type; - type_id.data.error_union.payload_type = payload_type; - - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) { - return existing_entry->value; - } - - Error err; - if ((err = type_resolve(g, err_set_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - - if ((err = type_resolve(g, payload_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - - ZigType *entry = new_type_table_entry(ZigTypeIdErrorUnion); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); - - entry->data.error_union.err_set_type = err_set_type; - entry->data.error_union.payload_type = payload_type; - - if (!type_has_bits(g, payload_type)) { - if (type_has_bits(g, err_set_type)) { - entry->size_in_bits = err_set_type->size_in_bits; - entry->abi_size = err_set_type->abi_size; - entry->abi_align = err_set_type->abi_align; - } else { - entry->size_in_bits = 0; - entry->abi_size = 0; - entry->abi_align = 0; - } - } else if (!type_has_bits(g, err_set_type)) { - entry->size_in_bits = payload_type->size_in_bits; - entry->abi_size = payload_type->abi_size; - entry->abi_align = payload_type->abi_align; - } else { - entry->abi_align = max(err_set_type->abi_align, payload_type->abi_align); - size_t field_sizes[2]; - size_t field_aligns[2]; - field_sizes[err_union_err_index] = err_set_type->abi_size; - field_aligns[err_union_err_index] = err_set_type->abi_align; - field_sizes[err_union_payload_index] = payload_type->abi_size; - field_aligns[err_union_payload_index] = payload_type->abi_align; - size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]); - entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align); - entry->size_in_bits = entry->abi_size * 8; - entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]); - } - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { - Error err; - - TypeId type_id = {}; - type_id.id = ZigTypeIdArray; - type_id.data.array.codegen = g; - type_id.data.array.child_type = child_type; - type_id.data.array.size = array_size; - type_id.data.array.sentinel = sentinel; - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) { - return existing_entry->value; - } - - size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); - - if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - codegen_report_errors_and_exit(g); - } - - ZigType *entry = new_type_table_entry(ZigTypeIdArray); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "[%" ZIG_PRI_u64, array_size); - if (sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); - } - buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - - entry->size_in_bits = child_type->size_in_bits * full_array_size; - entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align; - entry->abi_size = child_type->abi_size * full_array_size; - - entry->data.array.child_type = child_type; - entry->data.array.len = array_size; - entry->data.array.sentinel = sentinel; - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { - Error err; - assert(ptr_type->id == ZigTypeIdPointer); - assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown); - - ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent; - if (*parent_pointer) { - return *parent_pointer; - } - - // We use the pointer type's abi size below, so we have to resolve it now. - if ((err = type_resolve(g, ptr_type, ResolveStatusSizeKnown))) { - codegen_report_errors_and_exit(g); - } - - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "["); - if (ptr_type->data.pointer.sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, ptr_type->data.pointer.sentinel); - } - buf_appendf(&entry->name, "]"); - append_ptr_type_attrs(&entry->name, ptr_type); - - unsigned element_count = 2; - Buf *ptr_field_name = buf_create_from_str("ptr"); - Buf *len_field_name = buf_create_from_str("len"); - - entry->data.structure.resolve_status = ResolveStatusSizeKnown; - entry->data.structure.layout = ContainerLayoutAuto; - entry->data.structure.special = StructSpecialSlice; - entry->data.structure.src_field_count = element_count; - entry->data.structure.gen_field_count = element_count; - entry->data.structure.fields = alloc_type_struct_fields(element_count); - entry->data.structure.fields_by_name.init(element_count); - entry->data.structure.fields[slice_ptr_index]->name = ptr_field_name; - entry->data.structure.fields[slice_ptr_index]->type_entry = ptr_type; - entry->data.structure.fields[slice_ptr_index]->src_index = slice_ptr_index; - entry->data.structure.fields[slice_ptr_index]->gen_index = 0; - entry->data.structure.fields[slice_ptr_index]->offset = 0; - entry->data.structure.fields[slice_len_index]->name = len_field_name; - entry->data.structure.fields[slice_len_index]->type_entry = g->builtin_types.entry_usize; - entry->data.structure.fields[slice_len_index]->src_index = slice_len_index; - entry->data.structure.fields[slice_len_index]->gen_index = 1; - entry->data.structure.fields[slice_len_index]->offset = ptr_type->abi_size; - - entry->data.structure.fields_by_name.put(ptr_field_name, entry->data.structure.fields[slice_ptr_index]); - entry->data.structure.fields_by_name.put(len_field_name, entry->data.structure.fields[slice_len_index]); - - switch (type_requires_comptime(g, ptr_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeNo: - break; - case ReqCompTimeYes: - entry->data.structure.requires_comptime = true; - } - - if (!type_has_bits(g, ptr_type)) { - entry->data.structure.gen_field_count = 1; - entry->data.structure.fields[slice_ptr_index]->gen_index = SIZE_MAX; - entry->data.structure.fields[slice_len_index]->gen_index = 0; - } - - if (type_has_bits(g, ptr_type)) { - entry->size_in_bits = ptr_type->size_in_bits + g->builtin_types.entry_usize->size_in_bits; - entry->abi_size = ptr_type->abi_size + g->builtin_types.entry_usize->abi_size; - entry->abi_align = ptr_type->abi_align; - } else { - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - } - - *parent_pointer = entry; - return entry; -} - -static uint32_t node_line_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].line + 1; -} - -static uint32_t node_column_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].column + 1; -} - -ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, - Buf *bare_name) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); - - buf_init_from_str(&entry->name, full_name); - - ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = source_node ? node_line_onebased(source_node) : 0; - - // Note: duplicated in get_partial_container_type - entry->llvm_type = LLVMInt8Type(); - entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), full_name, - import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr, - import ? import->data.structure.root_struct->di_file : nullptr, - line); - entry->data.opaque.decl_node = source_node; - entry->data.opaque.bare_name = bare_name; - entry->data.opaque.decls_scope = create_decls_scope( - g, source_node, scope, entry, import, &entry->name); - - // The actual size is unknown, but the value must not be 0 because that - // is how type_has_bits is determined. - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = 1; - - return entry; -} - -ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) { - ZigType *fn_type = fn_entry->type_entry; - assert(fn_type->id == ZigTypeIdFn); - if (fn_type->data.fn.bound_fn_parent) - return fn_type->data.fn.bound_fn_parent; - - ZigType *bound_fn_type = new_type_table_entry(ZigTypeIdBoundFn); - bound_fn_type->data.bound_fn.fn_type = fn_type; - - buf_resize(&bound_fn_type->name, 0); - buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name)); - - fn_type->data.fn.bound_fn_parent = bound_fn_type; - return bound_fn_type; -} - -const char *calling_convention_name(CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: return "Unspecified"; - case CallingConventionC: return "C"; - case CallingConventionNaked: return "Naked"; - case CallingConventionAsync: return "Async"; - case CallingConventionInterrupt: return "Interrupt"; - case CallingConventionSignal: return "Signal"; - case CallingConventionStdcall: return "Stdcall"; - case CallingConventionFastcall: return "Fastcall"; - case CallingConventionVectorcall: return "Vectorcall"; - case CallingConventionThiscall: return "Thiscall"; - case CallingConventionAPCS: return "APCS"; - case CallingConventionAAPCS: return "AAPCS"; - case CallingConventionAAPCSVFP: return "AAPCSVFP"; - case CallingConventionInline: return "Inline"; - case CallingConventionSysV: return "SysV"; - case CallingConventionWin64: return "Win64"; - case CallingConventionPtxKernel: return "PtxKernel"; - case CallingConventionAmdgpuKernel: return "AmdgpuKernel"; - } - zig_unreachable(); -} - -bool calling_convention_allows_zig_types(CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionAsync: - case CallingConventionInline: - case CallingConventionPtxKernel: - return true; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionAmdgpuKernel: - return false; - } - zig_unreachable(); -} - -const char *address_space_name(AddressSpace as) { - switch (as) { - case AddressSpaceGeneric: return "generic"; - case AddressSpaceGS: return "gs"; - case AddressSpaceFS: return "fs"; - case AddressSpaceSS: return "ss"; - case AddressSpaceGlobal: return "global"; - case AddressSpaceConstant: return "constant"; - case AddressSpaceParam: return "param"; - case AddressSpaceShared: return "shared"; - case AddressSpaceLocal: return "local"; - } - zig_unreachable(); -} - -ZigType *get_stack_trace_type(CodeGen *g) { - if (g->stack_trace_type == nullptr) { - g->stack_trace_type = get_builtin_type(g, "StackTrace"); - assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown)); - } - return g->stack_trace_type; -} - -bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { - if (fn_type_id->cc == CallingConventionUnspecified - || fn_type_id->cc == CallingConventionInline) { - return handle_is_ptr(g, fn_type_id->return_type); - } - if (fn_type_id->cc != CallingConventionC) { - return false; - } - if (type_is_c_abi_int_bail(g, fn_type_id->return_type)) { - return false; - } - if (g->zig_target->arch == ZigLLVM_x86 || - g->zig_target->arch == ZigLLVM_x86_64 || - target_is_arm(g->zig_target) || - target_is_riscv(g->zig_target) || - target_is_wasm(g->zig_target) || - target_is_sparc(g->zig_target) || - target_is_ppc(g->zig_target)) - { - X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); - return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval; - } else if (g->zig_target->arch == ZigLLVM_mips || g->zig_target->arch == ZigLLVM_mipsel) { - return false; - } - zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481"); -} - -ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { - Error err; - auto table_entry = g->fn_type_table.maybe_get(fn_type_id); - if (table_entry) { - return table_entry->value; - } - if (fn_type_id->return_type != nullptr) { - if ((err = type_resolve(g, fn_type_id->return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - assert(fn_type_id->return_type->id != ZigTypeIdOpaque); - } else { - zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"); - } - - ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); - fn_type->data.fn.fn_type_id = *fn_type_id; - - // populate the name of the type - buf_resize(&fn_type->name, 0); - buf_appendf(&fn_type->name, "fn("); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; - - ZigType *param_type = param_info->type; - const char *comma = (i == 0) ? "" : ", "; - const char *noalias_str = param_info->is_noalias ? "noalias " : ""; - buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(¶m_type->name)); - } - - if (fn_type_id->is_var_args) { - const char *comma = (fn_type_id->param_count == 0) ? "" : ", "; - buf_appendf(&fn_type->name, "%s...", comma); - } - buf_appendf(&fn_type->name, ")"); - if (fn_type_id->alignment != 0) { - buf_appendf(&fn_type->name, " align(%" PRIu32 ")", fn_type_id->alignment); - } - if (fn_type_id->cc != CallingConventionUnspecified) { - buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); - } - buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name)); - - // The fn_type is a pointer; not to be confused with the raw function type. - fn_type->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - fn_type->abi_size = g->builtin_types.entry_usize->abi_size; - fn_type->abi_align = g->builtin_types.entry_usize->abi_align; - - g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); - - return fn_type; -} - -static ZigTypeId container_to_type(ContainerKind kind) { - switch (kind) { - case ContainerKindStruct: - return ZigTypeIdStruct; - case ContainerKindEnum: - return ZigTypeIdEnum; - case ContainerKindUnion: - return ZigTypeIdUnion; - case ContainerKindOpaque: - return ZigTypeIdOpaque; - } - zig_unreachable(); -} - -// This is like get_partial_container_type except it's for the implicit root struct of files. -static ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name, - RootStruct *root_struct) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - entry->data.structure.decls_scope = create_decls_scope(g, nullptr, nullptr, entry, entry, bare_name); - entry->data.structure.root_struct = root_struct; - entry->data.structure.layout = ContainerLayoutAuto; - - if (full_name[0] == '\0') { - buf_init_from_str(&entry->name, "(root)"); - } else { - buf_init_from_str(&entry->name, full_name); - } - - return entry; -} - -ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, - AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout) -{ - ZigTypeId type_id = container_to_type(kind); - ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope, bare_name); - - switch (kind) { - case ContainerKindStruct: - entry->data.structure.decl_node = decl_node; - entry->data.structure.layout = layout; - break; - case ContainerKindEnum: - entry->data.enumeration.decl_node = decl_node; - entry->data.enumeration.layout = layout; - break; - case ContainerKindUnion: - entry->data.unionation.decl_node = decl_node; - entry->data.unionation.layout = layout; - break; - case ContainerKindOpaque: { - ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = decl_node ? node_line_onebased(decl_node) : 0; - // Note: duplicated in get_opaque_type - entry->llvm_type = LLVMInt8Type(); - entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), full_name, - import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr, - import ? import->data.structure.root_struct->di_file : nullptr, - line); - entry->data.opaque.decl_node = decl_node; - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = 1; - break; - } - } - - buf_init_from_str(&entry->name, full_name); - - return entry; -} - -ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, UndefAllowed undef) -{ - Error err; - - ZigValue *result = g->pass1_arena->create(); - ZigValue *result_ptr = g->pass1_arena->create(); - result->special = ConstValSpecialUndef; - result->type = (type_entry == nullptr) ? g->builtin_types.entry_anytype : type_entry; - result_ptr->special = ConstValSpecialStatic; - result_ptr->type = get_pointer_to_type(g, result->type, false); - result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar; - result_ptr->data.x_ptr.special = ConstPtrSpecialRef; - result_ptr->data.x_ptr.data.ref.pointee = result; - - size_t backward_branch_count = 0; - size_t backward_branch_quota = default_backward_branch_quota; - if ((err = ir_eval_const_value(g, scope, node, result_ptr, - &backward_branch_count, &backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr, nullptr, undef))) - { - return g->invalid_inst_gen->value; - } - return result; -} - -Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type, - ZigValue *parent_type_val, bool *is_zero_bits) -{ - Error err; - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - - // Self-referencing types via pointers are allowed and have non-zero size - ZigType *ty = type_val->data.x_type; - while (ty->id == ZigTypeIdPointer && - !ty->data.pointer.resolve_loop_flag_zero_bits) - { - ty = ty->data.pointer.child_type; - } - - if ((ty->id == ZigTypeIdStruct && ty->data.structure.resolve_loop_flag_zero_bits) || - (ty->id == ZigTypeIdUnion && ty->data.unionation.resolve_loop_flag_zero_bits) || - (ty->id == ZigTypeIdPointer && ty->data.pointer.resolve_loop_flag_zero_bits)) - { - *is_zero_bits = false; - return ErrorNone; - } - - if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown))) - return err; - - *is_zero_bits = (type_val->data.x_type->abi_size == 0); - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - - if (parent_type_val == lazy_ptr_type->elem_type->value) { - // Does a struct which contains a pointer field to itself have bits? Yes. - *is_zero_bits = false; - return ErrorNone; - } else { - if (parent_type_val == nullptr) { - parent_type_val = type_val; - } - return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, parent_type, - parent_type_val, is_zero_bits); - } - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - - if (parent_type_val == lazy_ptr_type->elem_type->value) { - // Does a struct which contains a pointer field to itself have bits? Yes. - *is_zero_bits = false; - return ErrorNone; - } else { - if (parent_type_val == nullptr) { - parent_type_val = type_val; - } - return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, parent_type, - parent_type_val, is_zero_bits); - } - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - - // The sentinel counts as an extra element - if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) { - *is_zero_bits = true; - return ErrorNone; - } - - if ((err = type_val_resolve_zero_bits(g, lazy_array_type->elem_type->value, - parent_type, nullptr, is_zero_bits))) - return err; - - return ErrorNone; - } - case LazyValueIdOptType: - case LazyValueIdSliceType: - case LazyValueIdErrUnionType: - *is_zero_bits = false; - return ErrorNone; - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); - *is_zero_bits = lazy_fn_type->is_generic; - return ErrorNone; - } - } - zig_unreachable(); -} - -Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_opaque_type) { - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - if (type_val->data.x_type == g->builtin_types.entry_anytype) { - *is_opaque_type = false; - return ErrorNone; - } - *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdFnType: - case LazyValueIdOptType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - *is_opaque_type = false; - return ErrorNone; - } - zig_unreachable(); -} - -static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ZigValue *type_val) { - if (type_val->special != ConstValSpecialLazy) { - return type_requires_comptime(g, type_val->data.x_type); - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_slice_type->elem_type->value); - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type->value); - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type->value); - } - case LazyValueIdOptType: { - LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_opt_type->payload_type->value); - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_array_type->elem_type->value); - } - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_fn_type->is_generic) - return ReqCompTimeYes; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type->value)) { - case ReqCompTimeInvalid: - return ReqCompTimeInvalid; - case ReqCompTimeYes: - return ReqCompTimeYes; - case ReqCompTimeNo: - break; - } - size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length; - for (size_t i = 0; i < param_count; i += 1) { - AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i); - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) break; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i]->value)) { - case ReqCompTimeInvalid: - return ReqCompTimeInvalid; - case ReqCompTimeYes: - return ReqCompTimeYes; - case ReqCompTimeNo: - break; - } - } - return ReqCompTimeNo; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_err_union_type->payload_type->value); - } - } - zig_unreachable(); -} - -Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ZigValue *type_val, - size_t *abi_size, size_t *size_in_bits) -{ - Error err; - -start_over: - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - ZigType *ty = type_val->data.x_type; - if ((err = type_resolve(g, ty, ResolveStatusSizeKnown))) - return err; - *abi_size = ty->abi_size; - *size_in_bits = ty->size_in_bits; - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_slice_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size * 2; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2; - } - return ErrorNone; - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = 0; - *size_in_bits = 0; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } - return ErrorNone; - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = 0; - *size_in_bits = 0; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } - return ErrorNone; - } - case LazyValueIdFnType: - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - return ErrorNone; - case LazyValueIdOptType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - if ((err = ir_resolve_lazy(g, source_node, type_val))) - return err; - goto start_over; - } - zig_unreachable(); -} - -Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *type_val, uint32_t *abi_align) { - Error err; - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - ZigType *ty = type_val->data.x_type; - if (ty->id == ZigTypeIdPointer) { - *abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - } - if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown))) - return err; - *abi_align = ty->abi_align; - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdFnType: - *abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - case LazyValueIdOptType: { - if ((err = ir_resolve_lazy(g, nullptr, type_val))) - return err; - - return type_val_resolve_abi_align(g, source_node, type_val, abi_align); - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - - if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0) - return type_val_resolve_abi_align(g, source_node, lazy_array_type->elem_type->value, abi_align); - - *abi_align = 0; - return ErrorNone; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - uint32_t payload_abi_align; - if ((err = type_val_resolve_abi_align(g, source_node, lazy_err_union_type->payload_type->value, - &payload_abi_align))) - { - return err; - } - *abi_align = (payload_abi_align > g->err_tag_type->abi_align) ? - payload_abi_align : g->err_tag_type->abi_align; - return ErrorNone; - } - } - zig_unreachable(); -} - -static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigValue *type_val) { - if (type_val->special != ConstValSpecialLazy) { - return type_has_one_possible_value(g, type_val->data.x_type); - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: // it has the len field - case LazyValueIdOptType: // it has the optional bit - case LazyValueIdFnType: - return OnePossibleValueNo; - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length == 0) - return OnePossibleValueYes; - return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); - } - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - Error err; - bool zero_bits; - if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, nullptr, &zero_bits))) { - return OnePossibleValueInvalid; - } - if (zero_bits) { - return OnePossibleValueYes; - } else { - return OnePossibleValueNo; - } - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - switch (type_val_resolve_has_one_possible_value(g, lazy_err_union_type->err_set_type->value)) { - case OnePossibleValueInvalid: - return OnePossibleValueInvalid; - case OnePossibleValueNo: - return OnePossibleValueNo; - case OnePossibleValueYes: - return type_val_resolve_has_one_possible_value(g, lazy_err_union_type->payload_type->value); - } - } - } - zig_unreachable(); -} - -ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - Error err; - // Hot path for simple identifiers, to avoid unnecessary memory allocations. - if (node->type == NodeTypeIdentifier) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - Buf *variable_name = token_identifier_buf(root_struct, node->main_token); - if (buf_eql_str(variable_name, "_")) - goto abort_hot_path; - ZigType *primitive_type; - if ((err = get_primitive_type(g, variable_name, &primitive_type))) { - goto abort_hot_path; - } else { - return primitive_type; - } -abort_hot_path:; - } - ZigValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) - return g->builtin_types.entry_invalid; - src_assert(result->special == ConstValSpecialStatic, node); - src_assert(result->data.x_type != nullptr, node); - return result->data.x_type; -} - -ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { - ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); - buf_resize(&fn_type->name, 0); - buf_appendf(&fn_type->name, "fn("); - size_t i = 0; - for (; i < fn_type_id->next_param_index; i += 1) { - const char *comma_str = (i == 0) ? "" : ","; - buf_appendf(&fn_type->name, "%s%s", comma_str, - buf_ptr(&fn_type_id->param_info[i].type->name)); - } - for (; i < fn_type_id->param_count; i += 1) { - const char *comma_str = (i == 0) ? "" : ","; - buf_appendf(&fn_type->name, "%sanytype", comma_str); - } - buf_append_str(&fn_type->name, ")"); - if (fn_type_id->cc != CallingConventionUnspecified) { - buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); - } - buf_append_str(&fn_type->name, " anytype"); - - fn_type->data.fn.fn_type_id = *fn_type_id; - fn_type->data.fn.is_generic = true; - fn_type->abi_size = 0; - fn_type->size_in_bits = 0; - fn_type->abi_align = 0; - return fn_type; -} - -CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { - // Compatible with the C ABI - if (fn_proto->is_extern || fn_proto->is_export) - return CallingConventionC; - - if (fn_proto->fn_inline == FnInlineAlways) - return CallingConventionInline; - - return CallingConventionUnspecified; -} - -void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, CallingConvention cc, size_t param_count_alloc) { - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - - fn_type_id->cc = cc; - fn_type_id->param_count = fn_proto->params.length; - fn_type_id->param_info = heap::c_allocator.allocate(param_count_alloc); - fn_type_id->next_param_index = 0; - fn_type_id->is_var_args = fn_proto->is_var_args; -} - -static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - ZigValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), - nullptr, UndefBad); - if (type_is_invalid(align_result->type)) - return false; - - uint32_t align_bytes = bigint_as_u32(&align_result->data.x_bigint); - if (align_bytes == 0) { - add_node_error(g, node, buf_sprintf("alignment must be >= 1")); - return false; - } - if (!is_power_of_2(align_bytes)) { - add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); - return false; - } - - *result = align_bytes; - return true; -} - -static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { - ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(g, ptr_type); - ZigValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr, UndefBad); - if (type_is_invalid(result_val->type)) - return false; - - ZigValue *ptr_field = result_val->data.x_struct.fields[slice_ptr_index]; - ZigValue *len_field = result_val->data.x_struct.fields[slice_len_index]; - - assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; - if (array_val->data.x_array.special == ConstArraySpecialBuf) { - *out_buffer = array_val->data.x_array.data.s_buf; - return true; - } - expand_undef_array(g, array_val); - size_t len = bigint_as_usize(&len_field->data.x_bigint); - Buf *result = buf_alloc(); - buf_resize(result, len); - for (size_t i = 0; i < len; i += 1) { - size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; - ZigValue *char_val = &array_val->data.x_array.data.s_none.elements[new_index]; - if (char_val->special == ConstValSpecialUndef) { - add_node_error(g, node, buf_sprintf("use of undefined value")); - return false; - } - uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); - assert(big_c <= UINT8_MAX); - uint8_t c = (uint8_t)big_c; - buf_ptr(result)[i] = c; - } - *out_buffer = result; - return true; -} - -static Error emit_error_unless_type_allowed_in_packed_container(CodeGen *g, ZigType *type_entry, - AstNode *source_node, const char* container_name) -{ - Error err; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdVector: - return ErrorNone; - case ZigTypeIdArray: { - ZigType *elem_type = type_entry->data.array.child_type; - if ((err = emit_error_unless_type_allowed_in_packed_container(g, elem_type, source_node, container_name))) - return err; - // TODO revisit this when doing https://github.com/ziglang/zig/issues/1512 - size_t abi_size_in_bits = type_size(g, type_entry) * 8; - size_t size_in_bits = type_size_bits(g, type_entry); - if (abi_size_in_bits == size_in_bits) return ErrorNone; - add_node_error(g, source_node, - buf_sprintf("array of '%s' not allowed in packed %s due to padding bits (must be padded from %zu to %zu bits)", - buf_ptr(&elem_type->name), container_name, size_in_bits, abi_size_in_bits)); - return ErrorSemanticAnalyzeFail; - } - case ZigTypeIdStruct: - switch (type_entry->data.structure.layout) { - case ContainerLayoutPacked: - case ContainerLayoutExtern: - return ErrorNone; - case ContainerLayoutAuto: - add_node_error(g, source_node, - buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - zig_unreachable(); - case ZigTypeIdUnion: - switch (type_entry->data.unionation.layout) { - case ContainerLayoutPacked: - case ContainerLayoutExtern: - return ErrorNone; - case ContainerLayoutAuto: - add_node_error(g, source_node, - buf_sprintf("non-packed, non-extern union '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - zig_unreachable(); - case ZigTypeIdOptional: { - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, type_entry, &ptr_type))) return err; - if (ptr_type != nullptr) return ErrorNone; - - add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - case ZigTypeIdEnum: { - AstNode *decl_node = type_entry->data.enumeration.decl_node; - if (decl_node->data.container_decl.init_arg_expr != nullptr) { - return ErrorNone; - } - ErrorMsg *msg = add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - add_error_note(g, msg, decl_node, - buf_sprintf("enum declaration does not specify an integer tag type")); - return ErrorSemanticAnalyzeFail; - } - } - zig_unreachable(); -} - -static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry, - AstNode *source_node) -{ - return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "struct"); -} - -static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType *type_entry, - AstNode *source_node) -{ - return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union"); -} - -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result) { - Error err; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - *result = false; - return ErrorNone; - case ZigTypeIdUnreachable: - *result = position == ExternPositionFunctionReturn; - return ErrorNone; - case ZigTypeIdOpaque: - case ZigTypeIdBool: - *result = true; - return ErrorNone; - case ZigTypeIdInt: - switch (type_entry->data.integral.bit_count) { - case 8: - case 16: - case 32: - case 64: - case 128: - *result = true; - return ErrorNone; - default: - *result = false; - return ErrorNone; - } - case ZigTypeIdVector: - return type_allowed_in_extern(g, type_entry->data.vector.elem_type, ExternPositionOther, result); - case ZigTypeIdFloat: - *result = true; - return ErrorNone; - case ZigTypeIdArray: - if ((err = type_allowed_in_extern(g, type_entry->data.array.child_type, ExternPositionOther, result))) - return err; - *result = *result && - position != ExternPositionFunctionParameter && - position != ExternPositionFunctionReturn; - return ErrorNone; - case ZigTypeIdFn: - *result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc); - return ErrorNone; - case ZigTypeIdPointer: - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - bool has_bits; - if ((err = type_has_bits2(g, type_entry, &has_bits))) - return err; - *result = has_bits; - return ErrorNone; - case ZigTypeIdStruct: - *result = type_entry->data.structure.layout == ContainerLayoutExtern || - type_entry->data.structure.layout == ContainerLayoutPacked; - return ErrorNone; - case ZigTypeIdOptional: { - ZigType *child_type = type_entry->data.maybe.child_type; - if (child_type->id != ZigTypeIdPointer && child_type->id != ZigTypeIdFn) { - *result = false; - return ErrorNone; - } - bool is_nonnull_ptr; - if ((err = type_is_nonnull_ptr2(g, child_type, &is_nonnull_ptr))) - return err; - if (!is_nonnull_ptr) { - *result = false; - return ErrorNone; - } - return type_allowed_in_extern(g, child_type, ExternPositionOther, result); - } - case ZigTypeIdEnum: { - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type; - if (type_entry->data.enumeration.has_explicit_tag_type) - return type_allowed_in_extern(g, tag_int_type, position, result); - *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || - type_entry->data.enumeration.layout == ContainerLayoutPacked; - return ErrorNone; - } - case ZigTypeIdUnion: - *result = type_entry->data.unionation.layout == ContainerLayoutExtern || - type_entry->data.unionation.layout == ContainerLayoutPacked; - return ErrorNone; - } - zig_unreachable(); -} - -ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "@typeInfo(@typeInfo(@TypeOf(%s)).Fn.return_type.?).ErrorUnion.error_set", buf_ptr(&fn_entry->symbol_name)); - err_set_type->data.error_set.err_count = 0; - err_set_type->data.error_set.errors = nullptr; - err_set_type->data.error_set.infer_fn = fn_entry; - err_set_type->data.error_set.incomplete = true; - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - - return err_set_type; -} - -// Sync this with get_llvm_cc in codegen.cpp -Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc) { - Error ret = ErrorNone; - const char *allowed_platforms = nullptr; - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionAsync: - case CallingConventionInline: - break; - case CallingConventionInterrupt: - if (g->zig_target->arch != ZigLLVM_x86 - && g->zig_target->arch != ZigLLVM_x86_64 - && g->zig_target->arch != ZigLLVM_avr - && g->zig_target->arch != ZigLLVM_msp430) - { - allowed_platforms = "x86, x86_64, AVR, and MSP430"; - } - break; - case CallingConventionSignal: - if (g->zig_target->arch != ZigLLVM_avr) - allowed_platforms = "AVR"; - break; - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionThiscall: - if (g->zig_target->arch != ZigLLVM_x86) - allowed_platforms = "x86"; - break; - case CallingConventionVectorcall: - if (g->zig_target->arch != ZigLLVM_x86 - && !(target_is_arm(g->zig_target) && target_arch_pointer_bit_width(g->zig_target->arch) == 64)) - { - allowed_platforms = "x86 and AArch64"; - } - break; - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - if (!target_is_arm(g->zig_target)) - allowed_platforms = "ARM"; - break; - case CallingConventionSysV: - case CallingConventionWin64: - if (g->zig_target->arch != ZigLLVM_x86_64) - allowed_platforms = "x86_64"; - break; - case CallingConventionPtxKernel: - if (g->zig_target->arch != ZigLLVM_nvptx - && g->zig_target->arch != ZigLLVM_nvptx64) - { - allowed_platforms = "nvptx and nvptx64"; - } - break; - case CallingConventionAmdgpuKernel: - if (g->zig_target->arch != ZigLLVM_amdgcn) - allowed_platforms = "amdgcn and amdpal"; - - } - if (allowed_platforms != nullptr) { - add_node_error(g, source_node, buf_sprintf( - "callconv '%s' is only available on %s, not %s", - calling_convention_name(cc), allowed_platforms, - target_arch_name(g->zig_target->arch))); - ret = ErrorSemanticAnalyzeFail; - } - return ret; -} - -static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, ZigFn *fn_entry, - CallingConvention cc) -{ - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - Error err; - - FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, cc, proto_node->data.fn_proto.params.length); - - for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { - AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_comptime = param_node->data.param_decl.is_comptime; - bool param_is_var_args = param_node->data.param_decl.is_var_args; - - if (param_is_comptime) { - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - add_node_error(g, param_node, - buf_sprintf("comptime parameter not allowed in function with calling convention '%s'", - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - if (param_node->data.param_decl.type != nullptr) { - ZigType *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); - if (type_is_invalid(type_entry)) { - return g->builtin_types.entry_invalid; - } - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->type = type_entry; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - fn_type_id.next_param_index += 1; - } - - return get_generic_fn_type(g, &fn_type_id); - } else if (param_is_var_args) { - if (fn_type_id.cc == CallingConventionC) { - fn_type_id.param_count = fn_type_id.next_param_index; - continue; - } else { - add_node_error(g, param_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return g->builtin_types.entry_invalid; - } - } else if (param_node->data.param_decl.anytype_token != 0) { - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - add_node_error(g, param_node, - buf_sprintf("parameter of type 'anytype' not allowed in function with calling convention '%s'", - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - return get_generic_fn_type(g, &fn_type_id); - } - - ZigType *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); - if (type_is_invalid(type_entry)) { - return g->builtin_types.entry_invalid; - } - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return g->builtin_types.entry_invalid; - if (!type_has_bits(g, type_entry)) { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(&type_entry->name), calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - bool ok_type; - if ((err = type_allowed_in_extern(g, type_entry, ExternPositionFunctionParameter, &ok_type))) - return g->builtin_types.entry_invalid; - if (!ok_type) { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", - buf_ptr(&type_entry->name), - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - if(!is_valid_param_type(type_entry)){ - if(type_entry->id == ZigTypeIdOpaque){ - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of opaque type '%s' not allowed", buf_ptr(&type_entry->name))); - } else { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); - } - - return g->builtin_types.entry_invalid; - } - - switch (type_requires_comptime(g, type_entry)) { - case ReqCompTimeNo: - break; - case ReqCompTimeYes: - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' must be declared comptime", - buf_ptr(&type_entry->name))); - return g->builtin_types.entry_invalid; - case ReqCompTimeInvalid: - return g->builtin_types.entry_invalid; - } - - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->type = type_entry; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - } - - if (fn_proto->align_expr != nullptr) { - if (target_is_wasm(g->zig_target)) { - // In Wasm, specifying alignment of function pointers makes little sense - // since function pointers are in fact indices to a Wasm table, therefore - // any alignment check on those is invalid. This can cause unexpected - // behaviour when checking expected alignment with `@ptrToInt(fn_ptr)` - // or similar. This commit proposes to make `align` expressions a - // compile error when compiled to Wasm architecture. - // - // Some references: - // [1] [Mozilla: WebAssembly Tables](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables) - // [2] [Sunfishcode's Wasm Ref Manual](https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#indirect-call) - add_node_error(g, fn_proto->align_expr, - buf_sprintf("align(N) expr is not allowed on function prototypes in wasm32/wasm64")); - return g->builtin_types.entry_invalid; - } - if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &fn_type_id.alignment)) { - return g->builtin_types.entry_invalid; - } - fn_entry->align_bytes = fn_type_id.alignment; - } - - if (proto_node->data.fn_proto.callconv_expr != nullptr) { - if ((err = emit_error_unless_callconv_allowed_for_target(g, proto_node->data.fn_proto.callconv_expr, cc))) - return g->builtin_types.entry_invalid; - } - - ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); - if (type_is_invalid(specified_return_type)) { - fn_type_id.return_type = g->builtin_types.entry_invalid; - return g->builtin_types.entry_invalid; - } - - if(!is_valid_return_type(specified_return_type)){ - ErrorMsg* msg = add_node_error(g, fn_proto->return_type, - buf_sprintf("%s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name))); - Tld *tld = find_decl(g, &fn_entry->fndef_scope->base, &specified_return_type->name); - if (tld != nullptr) { - add_error_note(g, msg, tld->source_node, buf_sprintf("type declared here")); - } - return g->builtin_types.entry_invalid; - } - - if (fn_proto->auto_err_set) { - ZigType *inferred_err_set_type = get_auto_err_set_type(g, fn_entry); - if ((err = type_resolve(g, specified_return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type); - } else { - fn_type_id.return_type = specified_return_type; - } - - if (!calling_convention_allows_zig_types(fn_type_id.cc) && - fn_type_id.return_type->id != ZigTypeIdVoid) - { - if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - bool ok_type; - if ((err = type_allowed_in_extern(g, fn_type_id.return_type, ExternPositionFunctionReturn, &ok_type))) - return g->builtin_types.entry_invalid; - if (!ok_type) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", - buf_ptr(&fn_type_id.return_type->name), - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - switch (type_requires_comptime(g, fn_type_id.return_type)) { - case ReqCompTimeInvalid: - return g->builtin_types.entry_invalid; - case ReqCompTimeYes: - return get_generic_fn_type(g, &fn_type_id); - case ReqCompTimeNo: - break; - } - - return get_fn_type(g, &fn_type_id); -} - -bool is_valid_return_type(ZigType* type) { - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - return false; - default: - return true; - } - zig_unreachable(); -} - -bool is_valid_param_type(ZigType* type) { - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - case ZigTypeIdUnreachable: - return false; - default: - return true; - } - zig_unreachable(); -} - -bool type_is_invalid(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - return true; - case ZigTypeIdStruct: - return type_entry->data.structure.resolve_status == ResolveStatusInvalid; - case ZigTypeIdUnion: - return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; - case ZigTypeIdEnum: - return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid; - case ZigTypeIdFnFrame: - return type_entry->data.frame.reported_loop_err; - default: - return false; - } - zig_unreachable(); -} - -struct SrcField { - const char *name; - ZigType *ty; - unsigned align; -}; - -static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count, - unsigned min_abi_align) -{ - ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct); - - buf_init_from_str(&struct_type->name, type_name); - - struct_type->data.structure.src_field_count = field_count; - struct_type->data.structure.gen_field_count = 0; - struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; - struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - struct_type->data.structure.fields_by_name.init(field_count); - - size_t abi_align = min_abi_align; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - field->name = buf_create_from_str(fields[i].name); - field->type_entry = fields[i].ty; - field->src_index = i; - field->align = fields[i].align; - - if (type_has_bits(g, field->type_entry)) { - assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown)); - unsigned field_abi_align = max(field->align, field->type_entry->abi_align); - if (field_abi_align > abi_align) { - abi_align = field_abi_align; - } - } - - auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field); - assert(prev_entry == nullptr); - } - - size_t next_offset = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (!type_has_bits(g, field->type_entry)) - continue; - - field->offset = next_offset; - - // find the next non-zero-byte field for offset calculations - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (type_has_bits(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)) - break; - } - size_t next_abi_align; - if (next_src_field_index == field_count) { - next_abi_align = abi_align; - } else { - next_abi_align = max(fields[next_src_field_index].align, - struct_type->data.structure.fields[next_src_field_index]->type_entry->abi_align); - } - next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align); - } - - struct_type->abi_align = abi_align; - struct_type->abi_size = next_offset; - struct_type->size_in_bits = next_offset * 8; - - return struct_type; -} - -static size_t get_store_size_bytes(size_t size_in_bits) { - return (size_in_bits + 7) / 8; -} - -static size_t get_abi_align_bytes(size_t size_in_bits, size_t pointer_size_bytes) { - size_t store_size_bytes = get_store_size_bytes(size_in_bits); - if (store_size_bytes >= pointer_size_bytes) - return pointer_size_bytes; - return round_to_next_power_of_2(store_size_bytes); -} - -static size_t get_abi_size_bytes(size_t size_in_bits, size_t pointer_size_bytes) { - size_t store_size_bytes = get_store_size_bytes(size_in_bits); - size_t abi_align = get_abi_align_bytes(size_in_bits, pointer_size_bytes); - return align_forward(store_size_bytes, abi_align); -} - -ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field) { - Error err; - if (struct_field->type_entry == nullptr) { - if ((err = ir_resolve_lazy(g, struct_field->decl_node, struct_field->type_val))) { - return nullptr; - } - struct_field->type_entry = struct_field->type_val->data.x_type; - } - return struct_field->type_entry; -} - -static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown) - return ErrorNone; - - if ((err = resolve_struct_alignment(g, struct_type))) - return err; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (struct_type->data.structure.resolve_loop_flag_other) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); - - size_t field_count = struct_type->data.structure.src_field_count; - - bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - struct_type->data.structure.resolve_loop_flag_other = true; - - uint32_t *host_int_bytes = packed ? heap::c_allocator.allocate(struct_type->data.structure.gen_field_count) : nullptr; - - size_t packed_bits_offset = 0; - size_t next_offset = 0; - size_t first_packed_bits_offset_misalign = SIZE_MAX; - size_t gen_field_index = 0; - size_t size_in_bits = 0; - size_t abi_align = struct_type->abi_align; - - TypeStructField *last_packed_field = nullptr; - - // Calculate offsets - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX) - continue; - - field->gen_index = gen_field_index; - field->offset = next_offset; - - if (packed) { - ZigType *field_type = resolve_struct_field_type(g, field); - if (field_type == nullptr) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field->decl_node))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - last_packed_field = field; - size_t field_size_in_bits = type_size_bits(g, field_type); - size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; - - size_in_bits += field_size_in_bits; - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - // this field is not byte-aligned; it is part of the previous field with a bit offset - field->bit_offset_in_host = packed_bits_offset - first_packed_bits_offset_misalign; - - size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); - if (full_abi_size * 8 == full_bit_count) { - // next field recovers ABI alignment - host_int_bytes[gen_field_index] = full_abi_size; - gen_field_index += 1; - // TODO: https://github.com/ziglang/zig/issues/1512 - next_offset = next_field_offset(next_offset, abi_align, full_abi_size, 1); - size_in_bits = next_offset * 8; - - first_packed_bits_offset_misalign = SIZE_MAX; - } - } else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) { - first_packed_bits_offset_misalign = packed_bits_offset; - field->bit_offset_in_host = 0; - } else { - // This is a byte-aligned field (both start and end) in a packed struct. - host_int_bytes[gen_field_index] = field_type->size_in_bits / 8; - field->bit_offset_in_host = 0; - gen_field_index += 1; - // TODO: https://github.com/ziglang/zig/issues/1512 - next_offset = next_field_offset(next_offset, abi_align, field_type->size_in_bits / 8, 1); - size_in_bits = next_offset * 8; - } - packed_bits_offset = next_packed_bits_offset; - } else { - size_t field_abi_size; - size_t field_size_in_bits; - if ((err = type_val_resolve_abi_size(g, field->decl_node, field->type_val, - &field_abi_size, &field_size_in_bits))) - { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - gen_field_index += 1; - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (struct_type->data.structure.fields[next_src_field_index]->gen_index != SIZE_MAX) { - break; - } - } - size_t next_align = (next_src_field_index == field_count) ? - abi_align : struct_type->data.structure.fields[next_src_field_index]->align; - next_offset = next_field_offset(next_offset, abi_align, field_abi_size, next_align); - size_in_bits = next_offset * 8; - } - } - if (first_packed_bits_offset_misalign != SIZE_MAX) { - size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1); - next_offset = next_field_offset(next_offset, abi_align, full_abi_size, abi_align); - ZigType* last_field_type = last_packed_field->type_entry; - // If only last field is misaligned and it is of int type save it so we can generate proper code for it later - if (last_field_type->size_in_bits == full_bit_count && (last_field_type->id == ZigTypeIdInt || last_field_type->id == ZigTypeIdEnum)) { - struct_type->data.structure.misaligned_field = last_packed_field; - } - host_int_bytes[gen_field_index] = full_abi_size; - gen_field_index += 1; - } - - struct_type->abi_size = next_offset; - struct_type->size_in_bits = size_in_bits; - struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; - struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; - struct_type->data.structure.resolve_loop_flag_other = false; - struct_type->data.structure.host_int_bytes = host_int_bytes; - - - // Resolve types for fields - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = resolve_struct_field_type(g, field); - if (field_type == nullptr) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - if (struct_type->data.structure.layout == ContainerLayoutExtern) { - bool ok_type; - if ((err = type_allowed_in_extern(g, field_type, ExternPositionOther, &ok_type))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (!ok_type) { - add_node_error(g, field->decl_node, - buf_sprintf("extern structs cannot contain fields of type '%s'", - buf_ptr(&field_type->name))); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } - - return ErrorNone; -} - -static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - if ((err = resolve_union_zero_bits(g, union_type))) - return err; - if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - - AstNode *decl_node = union_type->data.structure.decl_node; - - if (union_type->data.unionation.resolve_loop_flag_other) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - // set temporary flag - union_type->data.unionation.resolve_loop_flag_other = true; - - TypeUnionField *most_aligned_union_member = nullptr; - uint32_t field_count = union_type->data.unionation.src_field_count; - bool packed = union_type->data.unionation.layout == ContainerLayoutPacked; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *field = &union_type->data.unionation.fields[i]; - if (field->gen_index == UINT32_MAX) - continue; - - AstNode *align_expr = nullptr; - if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) { - align_expr = field->decl_node->data.struct_field.align_expr; - } - if (align_expr != nullptr) { - if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, - &field->align)) - { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - add_node_error(g, field->decl_node, - buf_create_from_str("TODO implement field alignment syntax for unions. https://github.com/ziglang/zig/issues/3125")); - } else if (packed) { - field->align = 1; - } else if (field->type_entry != nullptr) { - if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - field->align = field->type_entry->abi_align; - } else { - if ((err = type_val_resolve_abi_align(g, field->decl_node, field->type_val, &field->align))) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field->decl_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } - - if (most_aligned_union_member == nullptr || field->align > most_aligned_union_member->align) { - most_aligned_union_member = field; - } - } - - // unset temporary flag - union_type->data.unionation.resolve_loop_flag_other = false; - union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; - union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (tag_type != nullptr && type_has_bits(g, tag_type)) { - if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (most_aligned_union_member == nullptr) { - union_type->abi_align = tag_type->abi_align; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.gen_union_index = SIZE_MAX; - } else if (tag_type->abi_align > most_aligned_union_member->align) { - union_type->abi_align = tag_type->abi_align; - union_type->data.unionation.gen_tag_index = 0; - union_type->data.unionation.gen_union_index = 1; - } else { - union_type->abi_align = most_aligned_union_member->align; - union_type->data.unionation.gen_union_index = 0; - union_type->data.unionation.gen_tag_index = 1; - } - } else { - union_type->abi_align = most_aligned_union_member? - most_aligned_union_member->align : 0; - union_type->data.unionation.gen_union_index = SIZE_MAX; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - } - - return ErrorNone; -} - -ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field) { - Error err; - if (union_field->type_entry == nullptr) { - if ((err = ir_resolve_lazy(g, union_field->decl_node, union_field->type_val))) { - return nullptr; - } - union_field->type_entry = union_field->type_val->data.x_type; - } - return union_field->type_entry; -} - -static Error resolve_union_type(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (union_type->data.unionation.resolve_status >= ResolveStatusSizeKnown) - return ErrorNone; - - if ((err = resolve_union_alignment(g, union_type))) - return err; - - AstNode *decl_node = union_type->data.unionation.decl_node; - - uint32_t field_count = union_type->data.unionation.src_field_count; - TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; - - assert(union_type->data.unionation.fields); - - size_t union_abi_size = 0; - size_t union_size_in_bits = 0; - - if (union_type->data.unionation.resolve_loop_flag_other) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - // set temporary flag - union_type->data.unionation.resolve_loop_flag_other = true; - - const bool is_packed = union_type->data.unionation.layout == ContainerLayoutPacked; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - ZigType *field_type = resolve_union_field_type(g, union_field); - if (field_type == nullptr) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (is_packed) { - if ((err = emit_error_unless_type_allowed_in_packed_union(g, field_type, union_field->decl_node))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - } - - if (type_is_invalid(union_type)) - return ErrorSemanticAnalyzeFail; - - if (!type_has_bits(g, field_type)) - continue; - - union_abi_size = max(union_abi_size, field_type->abi_size); - union_size_in_bits = max(union_size_in_bits, field_type->size_in_bits); - } - - // The union itself for now has to be treated as being independently aligned. - // See https://github.com/ziglang/zig/issues/2166. - if (most_aligned_union_member != nullptr) { - union_abi_size = align_forward(union_abi_size, most_aligned_union_member->align); - } - - // unset temporary flag - union_type->data.unionation.resolve_loop_flag_other = false; - union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; - union_type->data.unionation.union_abi_size = union_abi_size; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (tag_type != nullptr && type_has_bits(g, tag_type)) { - if ((err = type_resolve(g, tag_type, ResolveStatusSizeKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (most_aligned_union_member == nullptr) { - union_type->abi_size = tag_type->abi_size; - union_type->size_in_bits = tag_type->size_in_bits; - } else { - size_t field_sizes[2]; - size_t field_aligns[2]; - field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; - field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; - field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size; - field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->align; - size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); - union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); - union_type->size_in_bits = union_type->abi_size * 8; - } - } else { - union_type->abi_size = union_abi_size; - union_type->size_in_bits = union_size_in_bits; - } - - return ErrorNone; -} - -static Error type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty, bool *result) { - // Only integer types are allowed by the C ABI - if(ty->id != ZigTypeIdInt) { - *result = false; - return ErrorNone; - } - - // According to the ANSI C standard the enumeration type should be either a - // signed char, a signed integer or an unsigned one. But GCC/Clang allow - // other integral types as a compiler extension so let's accommodate them - // aswell. - return type_allowed_in_extern(g, ty, ExternPositionOther, result); -} - -static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { - Error err; - assert(enum_type->id == ZigTypeIdEnum); - - if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = enum_type->data.enumeration.decl_node; - - if (enum_type->data.enumeration.resolve_loop_flag) { - if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("enum '%s' depends on itself", - buf_ptr(&enum_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - enum_type->data.enumeration.resolve_loop_flag = true; - - uint32_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - assert(!enum_type->data.enumeration.fields); - field_count = (uint32_t)decl_node->data.container_decl.fields.length; - } else { - field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive; - } - - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = nullptr; - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - Scope *scope = &enum_type->data.enumeration.decls_scope->base; - - ZigType *tag_int_type; - if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { - tag_int_type = get_c_int_type(g, CIntTypeInt); - } else { - tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); - } - - enum_type->size_in_bits = tag_int_type->size_in_bits; - enum_type->abi_size = tag_int_type->abi_size; - enum_type->abi_align = tag_int_type->abi_align; - - ZigType *wanted_tag_int_type = nullptr; - if (decl_node->type == NodeTypeContainerDecl) { - if (decl_node->data.container_decl.init_arg_expr != nullptr) { - wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); - enum_type->data.enumeration.has_explicit_tag_type = true; - } - } else { - wanted_tag_int_type = enum_type->data.enumeration.tag_int_type; - enum_type->data.enumeration.has_explicit_tag_type = true; - } - - if (wanted_tag_int_type != nullptr) { - if (type_is_invalid(wanted_tag_int_type)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } else if (wanted_tag_int_type->id != ZigTypeIdInt && - wanted_tag_int_type->id != ZigTypeIdComptimeInt) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); - } else { - if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { - bool ok_type; - if ((err = type_is_valid_extern_enum_tag(g, wanted_tag_int_type, &ok_type))) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return err; - } - if (!ok_type) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("'%s' is not a valid tag type for an extern enum", - buf_ptr(&wanted_tag_int_type->name))); - add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid")); - return ErrorSemanticAnalyzeFail; - } - } - tag_int_type = wanted_tag_int_type; - } - } - - enum_type->data.enumeration.tag_int_type = tag_int_type; - enum_type->size_in_bits = tag_int_type->size_in_bits; - enum_type->abi_size = tag_int_type->abi_size; - enum_type->abi_align = tag_int_type->abi_align; - - BigInt bi_one; - bigint_init_unsigned(&bi_one, 1); - - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1); - if (buf_eql_str(last_field_node->data.struct_field.name, "_")) { - if (last_field_node->data.struct_field.value != nullptr) { - add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - if (decl_node->data.container_decl.init_arg_expr == nullptr) { - add_node_error(g, decl_node, buf_sprintf("non-exhaustive enum must specify size")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - enum_type->data.enumeration.non_exhaustive = true; - } else { - enum_type->data.enumeration.non_exhaustive = false; - } - } - - if (enum_type->data.enumeration.non_exhaustive) { - field_count -= 1; - if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) { - add_node_error(g, decl_node, buf_sprintf("non-exhaustive enum specifies every value")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - } - - if (decl_node->type == NodeTypeContainerDecl) { - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = heap::c_allocator.allocate(field_count); - enum_type->data.enumeration.fields_by_name.init(field_count); - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - TypeEnumField *last_enum_field = nullptr; - - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - type_enum_field->name = field_node->data.struct_field.name; - type_enum_field->decl_index = field_i; - type_enum_field->decl_node = field_node; - - if (field_node->data.struct_field.type != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type, - buf_sprintf("structs and unions, not enums, support field types")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - } else if (field_node->data.struct_field.align_expr != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.align_expr, - buf_sprintf("structs and unions, not enums, support field alignment")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - } - - if (buf_eql_str(type_enum_field->name, "_")) { - add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - - auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - continue; - } - - AstNode *tag_value = field_node->data.struct_field.value; - - if (tag_value != nullptr) { - // A user-specified value is available - ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - continue; - } - - assert(result->special != ConstValSpecialRuntime); - assert(result->type->id == ZigTypeIdInt || result->type->id == ZigTypeIdComptimeInt); - - bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); - } else { - // No value was explicitly specified: allocate the last value + 1 - // or, if this is the first element, zero - if (last_enum_field != nullptr) { - bigint_add(&type_enum_field->value, &last_enum_field->value, &bi_one); - } else { - bigint_init_unsigned(&type_enum_field->value, 0); - } - - // Make sure we can represent this number with tag_int_type - if (!bigint_fits_in_bits(&type_enum_field->value, - tag_int_type->size_in_bits, - tag_int_type->data.integral.is_signed)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &type_enum_field->value, 10); - add_node_error(g, field_node, - buf_sprintf("enumeration value %s too large for type '%s'", - buf_ptr(val_buf), buf_ptr(&tag_int_type->name))); - - break; - } - } - - // Make sure the value is unique - auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); - if (entry != nullptr && enum_type->data.enumeration.layout != ContainerLayoutExtern) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &type_enum_field->value, 10); - - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); - add_error_note(g, msg, entry->value, - buf_sprintf("other occurrence here")); - } - - last_enum_field = type_enum_field; - } - occupied_tag_values.deinit(); - } - - if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - enum_type->data.enumeration.resolve_loop_flag = false; - enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; - - return ErrorNone; -} - -static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (decl_node->data.container_decl.unsupported_explicit_backing_int) { - add_node_error(g, decl_node, buf_create_from_str( - "the stage1 compiler does not support explicit backing integer types on packed structs")); - return ErrorSemanticAnalyzeFail; - } - - if (struct_type->data.structure.resolve_loop_flag_zero_bits) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", - buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - struct_type->data.structure.resolve_loop_flag_zero_bits = true; - - size_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - field_count = decl_node->data.container_decl.fields.length; - struct_type->data.structure.src_field_count = (uint32_t)field_count; - - src_assert(struct_type->data.structure.fields == nullptr, decl_node); - struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_count = struct_type->data.structure.src_field_count; - - src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node); - } else zig_unreachable(); - - struct_type->data.structure.fields_by_name.init(field_count); - - Scope *scope = &struct_type->data.structure.decls_scope->base; - - size_t gen_field_index = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *type_struct_field = struct_type->data.structure.fields[i]; - - AstNode *field_node; - if (decl_node->type == NodeTypeContainerDecl) { - field_node = decl_node->data.container_decl.fields.at(i); - type_struct_field->name = field_node->data.struct_field.name; - type_struct_field->decl_node = field_node; - if (field_node->data.struct_field.comptime_token != 0) { - if (field_node->data.struct_field.value == nullptr) { - add_token_error(g, field_node->owner, - field_node->data.struct_field.comptime_token, - buf_sprintf("comptime struct field missing initialization value")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - type_struct_field->is_comptime = true; - } - - if (field_node->data.struct_field.type == nullptr) { - add_node_error(g, field_node, buf_sprintf("struct field missing type")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_node = type_struct_field->decl_node; - - src_assert(type_struct_field->type_entry != nullptr, field_node); - } else zig_unreachable(); - - auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - ZigValue *field_type_val; - if (decl_node->type == NodeTypeContainerDecl) { - field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - type_struct_field->type_val = field_type_val; - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_type_val = type_struct_field->type_val; - } else zig_unreachable(); - - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, field_node, - buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - type_struct_field->src_index = i; - type_struct_field->gen_index = SIZE_MAX; - - if (type_struct_field->is_comptime) - continue; - - switch (type_val_resolve_requires_comptime(g, field_type_val)) { - case ReqCompTimeYes: - struct_type->data.structure.requires_comptime = true; - break; - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field_node, - buf_create_from_str("while checking this field")); - } - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeNo: - break; - } - - bool field_is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, nullptr, &field_is_zero_bits))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_zero_bits) - continue; - - type_struct_field->gen_index = gen_field_index; - gen_field_index += 1; - } - - struct_type->data.structure.resolve_loop_flag_zero_bits = false; - struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; - if (gen_field_index != 0) { - struct_type->abi_size = SIZE_MAX; - struct_type->size_in_bits = SIZE_MAX; - } - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; - return ErrorNone; -} - -static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - if ((err = resolve_struct_zero_bits(g, struct_type))) - return err; - if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (struct_type->data.structure.resolve_loop_flag_other) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - struct_type->data.structure.resolve_loop_flag_other = true; - - size_t field_count = struct_type->data.structure.src_field_count; - bool packed = struct_type->data.structure.layout == ContainerLayoutPacked; - - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX) - continue; - - AstNode *align_expr = (field->decl_node->type == NodeTypeStructField) ? - field->decl_node->data.struct_field.align_expr : nullptr; - if (align_expr != nullptr) { - if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, - &field->align)) - { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else if (packed) { - field->align = 1; - } else { - if ((err = type_val_resolve_abi_align(g, field->decl_node, field->type_val, &field->align))) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field->decl_node, - buf_create_from_str("while checking this field")); - } - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } - - if (field->align > struct_type->abi_align) { - struct_type->abi_align = field->align; - } - } - - if (!type_has_bits(g, struct_type)) { - assert(struct_type->abi_align == 0); - } - - struct_type->data.structure.resolve_loop_flag_other = false; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { - return ErrorSemanticAnalyzeFail; - } - - struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; - return ErrorNone; -} - -static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = union_type->data.unionation.decl_node; - - if (union_type->data.unionation.resolve_loop_flag_zero_bits) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", - buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - union_type->data.unionation.resolve_loop_flag_zero_bits = true; - - uint32_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - assert(union_type->data.unionation.fields == nullptr); - field_count = (uint32_t)decl_node->data.container_decl.fields.length; - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); - union_type->data.unionation.fields_by_name.init(field_count); - } else { - field_count = union_type->data.unionation.src_field_count; - assert(field_count == 0 || union_type->data.unionation.fields != nullptr); - } - - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - Scope *scope = &union_type->data.unionation.decls_scope->base; - - HashMap occupied_tag_values = {}; - - bool is_auto_enum; // union(enum) or union(enum(expr)) - bool is_explicit_enum; // union(expr) - AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr) - if (decl_node->type == NodeTypeContainerDecl) { - is_auto_enum = decl_node->data.container_decl.auto_enum; - is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr; - enum_type_node = decl_node->data.container_decl.init_arg_expr; - } else { - is_auto_enum = false; - is_explicit_enum = union_type->data.unionation.tag_type != nullptr; - enum_type_node = nullptr; - } - union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum; - - bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto; - bool want_safety = (field_count >= 2) - && (is_auto_layout || is_explicit_enum) - && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); - ZigType *tag_type; - bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety); - bool *covered_enum_fields; - bool *is_zero_bits = heap::c_allocator.allocate(field_count); - if (create_enum_type) { - occupied_tag_values.init(field_count); - - ZigType *tag_int_type; - if (enum_type_node != nullptr) { - tag_int_type = analyze_type_expr(g, scope, enum_type_node); - if (type_is_invalid(tag_int_type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_int_type->id != ZigTypeIdInt && tag_int_type->id != ZigTypeIdComptimeInt) { - add_node_error(g, enum_type_node, - buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_int_type->id == ZigTypeIdInt) { - BigInt bi; - bigint_init_unsigned(&bi, field_count - 1); - if (!bigint_fits_in_bits(&bi, - tag_int_type->data.integral.bit_count, - tag_int_type->data.integral.is_signed)) - { - ErrorMsg *msg = add_node_error(g, enum_type_node, - buf_sprintf("specified integer tag type cannot represent every field")); - add_error_note(g, msg, enum_type_node, - buf_sprintf("type %s cannot fit values in range 0...%" PRIu32, - buf_ptr(&tag_int_type->name), field_count - 1)); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } else { - tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); - } - - tag_type = new_type_table_entry(ZigTypeIdEnum); - buf_resize(&tag_type->name, 0); - buf_appendf(&tag_type->name, "@typeInfo(%s).Union.tag_type.?", buf_ptr(&union_type->name)); - tag_type->llvm_type = tag_int_type->llvm_type; - tag_type->llvm_di_type = tag_int_type->llvm_di_type; - tag_type->abi_size = tag_int_type->abi_size; - tag_type->abi_align = tag_int_type->abi_align; - tag_type->size_in_bits = tag_int_type->size_in_bits; - - tag_type->data.enumeration.tag_int_type = tag_int_type; - tag_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; - tag_type->data.enumeration.decl_node = decl_node; - tag_type->data.enumeration.layout = ContainerLayoutAuto; - tag_type->data.enumeration.src_field_count = field_count; - tag_type->data.enumeration.fields = heap::c_allocator.allocate(field_count); - tag_type->data.enumeration.fields_by_name.init(field_count); - tag_type->data.enumeration.decls_scope = create_decls_scope( - g, nullptr, nullptr, tag_type, get_scope_import(scope), &tag_type->name); - } else if (enum_type_node != nullptr) { - tag_type = analyze_type_expr(g, scope, enum_type_node); - } else { - if (decl_node->type == NodeTypeContainerDecl) { - tag_type = nullptr; - } else { - tag_type = union_type->data.unionation.tag_type; - } - } - if (tag_type != nullptr) { - if (type_is_invalid(tag_type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_type->id != ZigTypeIdEnum) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, enum_type_node != nullptr ? enum_type_node : decl_node, - buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&tag_type->name))); - return ErrorSemanticAnalyzeFail; - } - if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) { - assert(g->errors.length != 0); - return err; - } - covered_enum_fields = heap::c_allocator.allocate(tag_type->data.enumeration.src_field_count); - } - union_type->data.unionation.tag_type = tag_type; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); - union_field->name = field_node->data.struct_field.name; - union_field->decl_node = field_node; - union_field->gen_index = UINT32_MAX; - is_zero_bits[i] = false; - - auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, union_field->decl_node, - buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (field_node->data.struct_field.type == nullptr) { - if (is_auto_enum || is_explicit_enum) { - union_field->type_entry = g->builtin_types.entry_void; - is_zero_bits[i] = true; - } else { - add_node_error(g, field_node, buf_sprintf("union field missing type")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else { - ZigValue *field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - union_field->type_val = field_type_val; - } - - if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, - buf_create_from_str("untagged union field assignment")); - add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); - } - } - - if (union_field->type_val != nullptr) { - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, union_field->decl_node, - buf_create_from_str( - "opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - switch (type_val_resolve_requires_comptime(g, union_field->type_val)) { - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; - } - - if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - - if (create_enum_type) { - union_field->enum_field = &tag_type->data.enumeration.fields[i]; - union_field->enum_field->name = union_field->name; - union_field->enum_field->decl_index = i; - union_field->enum_field->decl_node = union_field->decl_node; - - auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field); - assert(prev_entry == nullptr); // caught by union de-duplicator above - - AstNode *tag_value = decl_node->type == NodeTypeContainerDecl - ? union_field->decl_node->data.struct_field.value : nullptr; - - // In this first pass we resolve explicit tag values. - // In a second pass we will fill in the unspecified ones. - if (tag_value != nullptr) { - ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(result->special != ConstValSpecialRuntime); - assert(result->type->id == ZigTypeIdInt); - auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); - if (entry == nullptr) { - bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); - } else { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result->data.x_bigint, 10); - - ErrorMsg *msg = add_node_error(g, tag_value, - buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); - add_error_note(g, msg, entry->value, - buf_sprintf("other occurrence here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } else if (tag_type != nullptr) { - union_field->enum_field = find_enum_type_field(tag_type, union_field->name); - if (union_field->enum_field == nullptr) { - ErrorMsg *msg = add_node_error(g, union_field->decl_node, - buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name))); - add_error_note(g, msg, tag_type->data.enumeration.decl_node, - buf_sprintf("enum declared here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - covered_enum_fields[union_field->enum_field->decl_index] = true; - } else { - union_field->enum_field = heap::c_allocator.create(); - union_field->enum_field->name = union_field->name; - union_field->enum_field->decl_index = i; - bigint_init_unsigned(&union_field->enum_field->value, i); - } - assert(union_field->enum_field != nullptr); - } - - uint32_t gen_field_index = 0; - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (!is_zero_bits[i]) { - union_field->gen_index = gen_field_index; - gen_field_index += 1; - } - } - heap::c_allocator.deallocate(is_zero_bits, field_count); - - bool src_have_tag = is_auto_enum || is_explicit_enum; - - if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { - const char *qual_str; - switch (union_type->data.unionation.layout) { - case ContainerLayoutAuto: - zig_unreachable(); - case ContainerLayoutPacked: - qual_str = "packed"; - break; - case ContainerLayoutExtern: - qual_str = "extern"; - break; - } - AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node; - add_node_error(g, source_node, - buf_sprintf("%s union does not support enum tag type", qual_str)); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (create_enum_type) { - if (decl_node->type == NodeTypeContainerDecl) { - // Now iterate again and populate the unspecified tag values - uint32_t next_maybe_unoccupied_index = 0; - - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; - AstNode *tag_value = field_node->data.struct_field.value; - - if (tag_value == nullptr) { - if (occupied_tag_values.size() == 0) { - bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - } else { - BigInt proposed_value; - for (;;) { - bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - auto entry = occupied_tag_values.put_unique(proposed_value, field_node); - if (entry != nullptr) { - continue; - } - break; - } - bigint_init_bigint(&union_field->enum_field->value, &proposed_value); - } - } - } - } - } else if (tag_type != nullptr) { - for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; - if (!covered_enum_fields[i]) { - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; - AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); - add_error_note(g, msg, field_node, - buf_sprintf("declared here")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - } - } - heap::c_allocator.deallocate(covered_enum_fields, tag_type->data.enumeration.src_field_count); - } - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) { - return ErrorSemanticAnalyzeFail; - } - - union_type->data.unionation.resolve_loop_flag_zero_bits = false; - - union_type->data.unionation.gen_field_count = gen_field_index; - bool zero_bits = gen_field_index == 0 && - (tag_type == nullptr || !type_has_bits(g, tag_type)); - if (!zero_bits) { - union_type->abi_size = SIZE_MAX; - union_type->size_in_bits = SIZE_MAX; - } - - union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown; - - return ErrorNone; -} - -static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) { - Error err = ErrorNone; - AstNode *container_node = opaque_type->data.opaque.decl_node; - if (container_node != nullptr) { - assert(container_node->type == NodeTypeContainerDecl); - AstNodeContainerDecl *container_decl = &container_node->data.container_decl; - for (size_t i = 0; i < container_decl->fields.length; i++) { - AstNode *field_node = container_decl->fields.items[i]; - add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields")); - err = ErrorSemanticAnalyzeFail; - } - } - return err; -} - -void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) { - if (g->root_import == container_type || buf_len(&container_type->name) == 0) return; - buf_append_buf(buf, &container_type->name); - buf_append_char(buf, NAMESPACE_SEP_CHAR); -} - -static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool is_test) { - buf_resize(buf, 0); - - Scope *scope = tld->parent_scope; - while (scope->id != ScopeIdDecls) { - scope = scope->parent; - } - ScopeDecls *decls_scope = reinterpret_cast(scope); - append_namespace_qualification(g, buf, decls_scope->container_type); - if (is_test) { - buf_append_str(buf, "test \""); - buf_append_buf(buf, tld->name); - buf_append_char(buf, '"'); - } else { - buf_append_buf(buf, tld->name); - } -} - -static ZigFn *create_fn_raw(CodeGen *g, bool is_noinline) { - ZigFn *fn_entry = heap::c_allocator.create(); - fn_entry->stage1_zir = heap::c_allocator.create(); - fn_entry->is_noinline = is_noinline; - - return fn_entry; -} - -ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - - ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline == FnInlineNever); - - fn_entry->proto_node = proto_node; - fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : - proto_node->data.fn_proto.fn_def_node->data.fn_def.body; - - fn_entry->analyzed_executable.source_node = fn_entry->body_node; - - return fn_entry; -} - -ZigType *get_test_fn_type(CodeGen *g) { - if (g->test_fn_type) - return g->test_fn_type; - - FnTypeId fn_type_id = {0}; - fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set, - g->builtin_types.entry_void); - g->test_fn_type = get_fn_type(g, &fn_type_id); - return g->test_fn_type; -} - -void add_var_export(CodeGen *g, ZigVar *var, const char *symbol_name, GlobalLinkageId linkage) { - GlobalExport *global_export = var->export_list.add_one(); - memset(global_export, 0, sizeof(GlobalExport)); - buf_init_from_str(&global_export->name, symbol_name); - global_export->linkage = linkage; -} - -void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc) { - CallingConvention winapi_cc = g->zig_target->arch == ZigLLVM_x86 - ? CallingConventionStdcall - : CallingConventionC; - - if (cc == CallingConventionC && strcmp(symbol_name, "main") == 0 && g->link_libc) { - g->stage1.have_c_main = true; - } else if (cc == winapi_cc && g->zig_target->os == OsWindows) { - if (strcmp(symbol_name, "WinMain") == 0) { - g->stage1.have_winmain = true; - } else if (strcmp(symbol_name, "wWinMain") == 0) { - g->stage1.have_wwinmain = true; - } else if (strcmp(symbol_name, "WinMainCRTStartup") == 0) { - g->stage1.have_winmain_crt_startup = true; - } else if (strcmp(symbol_name, "wWinMainCRTStartup") == 0) { - g->stage1.have_wwinmain_crt_startup = true; - } else if (strcmp(symbol_name, "DllMainCRTStartup") == 0) { - g->stage1.have_dllmain_crt_startup = true; - } - } - - GlobalExport *fn_export = fn_table_entry->export_list.add_one(); - memset(fn_export, 0, sizeof(GlobalExport)); - buf_init_from_str(&fn_export->name, symbol_name); - fn_export->linkage = linkage; -} - -static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { - AstNode *source_node = tld_fn->base.source_node; - if (source_node->type == NodeTypeFnProto) { - AstNodeFnProto *fn_proto = &source_node->data.fn_proto; - - AstNode *fn_def_node = fn_proto->fn_def_node; - - ZigFn *fn_table_entry = create_fn(g, source_node); - tld_fn->fn_entry = fn_table_entry; - - bool is_extern = (fn_table_entry->body_node == nullptr); - if (fn_proto->is_export || is_extern) { - buf_init_from_buf(&fn_table_entry->symbol_name, tld_fn->base.name); - } else { - get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, false); - } - - if (!is_extern) { - fn_table_entry->fndef_scope = create_fndef_scope(g, - fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry); - - for (size_t i = 0; i < fn_proto->params.length; i += 1) { - AstNode *param_node = fn_proto->params.at(i); - assert(param_node->type == NodeTypeParamDecl); - if (param_node->data.param_decl.name == nullptr) { - add_node_error(g, param_node, buf_sprintf("missing parameter name")); - } - } - } else { - fn_table_entry->inferred_async_node = inferred_async_none; - g->external_symbol_names.put_unique(tld_fn->base.name, &tld_fn->base); - } - - Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; - - CallingConvention cc; - if (fn_proto->callconv_expr != nullptr) { - if (fn_proto->fn_inline == FnInlineAlways) { - add_node_error(g, fn_proto->callconv_expr, buf_sprintf("explicit callconv incompatible with inline keyword")); - } - ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); - - ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr, - cc_enum_value, nullptr, UndefBad); - if (type_is_invalid(result_val->type)) { - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - - cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); - } else { - cc = cc_from_fn_proto(fn_proto); - } - - if (fn_proto->section_expr != nullptr) { - if (!analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name)) { - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - } - - fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry, cc); - - if (type_is_invalid(fn_table_entry->type_entry)) { - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - - const CallingConvention fn_cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; - - if (fn_proto->is_export) { - switch (fn_cc) { - case CallingConventionAsync: - add_node_error(g, fn_def_node, - buf_sprintf("exported function cannot be async")); - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - case CallingConventionInline: - add_node_error(g, fn_def_node, - buf_sprintf("exported function cannot be inline")); - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), - GlobalLinkageIdStrong, fn_cc); - break; - case CallingConventionUnspecified: - // An exported function without a specific calling - // convention defaults to C - add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), - GlobalLinkageIdStrong, CallingConventionC); - break; - } - } - - if (!fn_table_entry->type_entry->data.fn.is_generic) { - if (fn_def_node) - g->fn_defs.append(fn_table_entry); - } - - // if the calling convention implies that it cannot be async, we save that for later - // and leave the value to be nullptr to indicate that we have not emitted possible - // compile errors for improperly calling async functions. - if (fn_cc == CallingConventionAsync) { - fn_table_entry->inferred_async_node = fn_table_entry->proto_node; - } - } else if (source_node->type == NodeTypeTestDecl) { - ZigFn *fn_table_entry = create_fn_raw(g, false); - - get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, true); - - tld_fn->fn_entry = fn_table_entry; - - fn_table_entry->proto_node = source_node; - fn_table_entry->fndef_scope = create_fndef_scope(g, source_node, tld_fn->base.parent_scope, fn_table_entry); - fn_table_entry->type_entry = get_test_fn_type(g); - fn_table_entry->body_node = source_node->data.test_decl.body; - - g->fn_defs.append(fn_table_entry); - g->test_fns.append(fn_table_entry); - - } else { - zig_unreachable(); - } -} - -static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { - assert(tld_comptime->base.source_node->type == NodeTypeCompTime); - AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; - analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, - nullptr, UndefBad); -} - -static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { - bool is_export = false; - if (tld->id == TldIdVar) { - assert(tld->source_node->type == NodeTypeVariableDeclaration); - is_export = tld->source_node->data.variable_declaration.is_export; - } else if (tld->id == TldIdFn) { - assert(tld->source_node->type == NodeTypeFnProto); - is_export = tld->source_node->data.fn_proto.is_export; - - if (!tld->source_node->data.fn_proto.is_extern && - tld->source_node->data.fn_proto.fn_def_node == nullptr) - { - add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body")); - return; - } - if (!tld->source_node->data.fn_proto.is_extern && - tld->source_node->data.fn_proto.is_var_args) - { - add_node_error(g, tld->source_node, buf_sprintf("non-extern function is variadic")); - return; - } - } else if (tld->id == TldIdUsingNamespace) { - g->resolve_queue.append(tld); - } - if (is_export) { - g->resolve_queue.append(tld); - - auto entry = g->exported_symbol_names.put_unique(tld->name, tld); - if (entry) { - AstNode *other_source_node = entry->value->source_node; - ErrorMsg *msg = add_node_error(g, tld->source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here")); - } - } - - if (tld->name != nullptr) { - auto entry = decls_scope->decl_table.put_unique(tld->name, tld); - if (entry) { - Tld *other_tld = entry->value; - if (other_tld->id == TldIdVar) { - ZigVar *var = reinterpret_cast(other_tld)->var; - if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { - return; // already reported compile error - } - } - ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition here")); - return; - } - } -} - -static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { - assert(node->type == NodeTypeTestDecl); - - if (!g->is_test_build) - return; - - ZigType *import = get_scope_import(&decls_scope->base); - if (import->data.structure.root_struct->package != g->main_pkg) - return; - - Buf *decl_name_buf = node->data.test_decl.name; - Buf *test_name; - - if (decl_name_buf != nullptr) { - test_name = g->test_name_prefix ? - buf_sprintf("%s%s", buf_ptr(g->test_name_prefix), buf_ptr(decl_name_buf)) : decl_name_buf; - - if (g->test_filter != nullptr && strstr(buf_ptr(test_name), buf_ptr(g->test_filter)) == nullptr) { - return; - } - } else { - // Unnamed test blocks are always executed. - test_name = buf_sprintf("%s", g->test_name_prefix ? buf_ptr(g->test_name_prefix) : ""); - } - - TldFn *tld_fn = heap::c_allocator.create(); - init_tld(&tld_fn->base, TldIdFn, test_name, VisibModPrivate, node, &decls_scope->base); - g->resolve_queue.append(&tld_fn->base); -} - -static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { - assert(node->type == NodeTypeCompTime); - - TldCompTime *tld_comptime = heap::c_allocator.create(); - init_tld(&tld_comptime->base, TldIdCompTime, nullptr, VisibModPrivate, node, &decls_scope->base); - g->resolve_queue.append(&tld_comptime->base); -} - -void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, - Scope *parent_scope) -{ - tld->id = id; - tld->name = name; - tld->visib_mod = visib_mod; - tld->source_node = source_node; - tld->import = source_node ? source_node->owner : nullptr; - tld->parent_scope = parent_scope; -} - -void update_compile_var(CodeGen *g, Buf *name, ZigValue *value) { - ScopeDecls *builtin_scope = get_container_scope(g->compile_var_import); - Tld *tld = find_container_decl(g, builtin_scope, name); - assert(tld != nullptr); - resolve_top_level_decl(g, tld, tld->source_node, false); - assert(tld->id == TldIdVar && tld->resolution == TldResolutionOk); - TldVar *tld_var = (TldVar *)tld; - copy_const_val(g, tld_var->var->const_value, value); - tld_var->var->var_type = value->type; - tld_var->var->align_bytes = get_abi_alignment(g, value->type); -} - -void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { - switch (node->type) { - case NodeTypeFnDef: - scan_decls(g, decls_scope, node->data.fn_def.fn_proto); - break; - case NodeTypeVariableDeclaration: - { - Buf *name = node->data.variable_declaration.symbol; - VisibMod visib_mod = node->data.variable_declaration.visib_mod; - TldVar *tld_var = heap::c_allocator.create(); - init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base); - tld_var->extern_lib_name = node->data.variable_declaration.lib_name; - add_top_level_decl(g, decls_scope, &tld_var->base); - break; - } - case NodeTypeFnProto: - { - // if the name is missing, we immediately announce an error - Buf *fn_name = node->data.fn_proto.name; - if (fn_name == nullptr) { - add_node_error(g, node, buf_sprintf("missing function name")); - break; - } - - VisibMod visib_mod = node->data.fn_proto.visib_mod; - TldFn *tld_fn = heap::c_allocator.create(); - init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base); - tld_fn->extern_lib_name = node->data.fn_proto.lib_name; - add_top_level_decl(g, decls_scope, &tld_fn->base); - - break; - } - case NodeTypeUsingNamespace: { - VisibMod visib_mod = node->data.using_namespace.visib_mod; - TldUsingNamespace *tld_using_namespace = heap::c_allocator.create(); - init_tld(&tld_using_namespace->base, TldIdUsingNamespace, nullptr, visib_mod, node, &decls_scope->base); - add_top_level_decl(g, decls_scope, &tld_using_namespace->base); - decls_scope->use_decls.append(tld_using_namespace); - break; - } - case NodeTypeTestDecl: - preview_test_decl(g, node, decls_scope); - break; - case NodeTypeCompTime: - preview_comptime_decl(g, node, decls_scope); - break; - case NodeTypeContainerDecl: - case NodeTypeNoSuspend: - case NodeTypeParamDecl: - case NodeTypeReturnExpr: - case NodeTypeDefer: - case NodeTypeBlock: - case NodeTypeGroupedExpr: - case NodeTypeBinOpExpr: - case NodeTypeCatchExpr: - case NodeTypeFnCallExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeSliceExpr: - case NodeTypeFloatLiteral: - case NodeTypeIntLiteral: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeIdentifier: - case NodeTypePrefixOpExpr: - case NodeTypePointerType: - case NodeTypeIfBoolExpr: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeUnreachable: - case NodeTypeAsmExpr: - case NodeTypeFieldAccessExpr: - case NodeTypePtrDeref: - case NodeTypeUnwrapOptional: - case NodeTypeStructField: - case NodeTypeContainerInitExpr: - case NodeTypeStructValueField: - case NodeTypeArrayType: - case NodeTypeInferredArrayType: - case NodeTypeErrorType: - case NodeTypeIfErrorExpr: - case NodeTypeIfOptional: - case NodeTypeErrorSetDecl: - case NodeTypeResume: - case NodeTypeAwaitExpr: - case NodeTypeSuspend: - case NodeTypeEnumLiteral: - case NodeTypeAnyFrameType: - case NodeTypeErrorSetField: - case NodeTypeAnyTypeField: - zig_unreachable(); - } -} - -static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) { - ZigType *type_entry = tld_container->type_entry; - assert(type_entry); - - switch (type_entry->id) { - case ZigTypeIdStruct: - return resolve_struct_type(g, tld_container->type_entry); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, tld_container->type_entry); - case ZigTypeIdUnion: - return resolve_union_type(g, tld_container->type_entry); - case ZigTypeIdOpaque: - return resolve_opaque_type(g, tld_container->type_entry); - default: - zig_unreachable(); - } -} - -ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - return g->builtin_types.entry_invalid; - case ZigTypeIdOpaque: - if (source_node->is_extern) - return type_entry; - ZIG_FALLTHROUGH; - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - add_node_error(g, source_node->type, buf_sprintf("variable of type '%s' not allowed", - buf_ptr(&type_entry->name))); - return g->builtin_types.entry_invalid; - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return type_entry; - } - zig_unreachable(); -} - -// Set name to nullptr to make the variable anonymous (not visible to programmer). -// TODO merge with definition of add_local_var in ir.cpp -ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ZigValue *const_value, Tld *src_tld, ZigType *var_type) -{ - Error err; - assert(const_value != nullptr); - assert(var_type != nullptr); - - ZigVar *variable_entry = heap::c_allocator.create(); - variable_entry->const_value = const_value; - variable_entry->var_type = var_type; - variable_entry->parent_scope = parent_scope; - variable_entry->shadowable = false; - variable_entry->src_arg_index = SIZE_MAX; - - assert(name); - variable_entry->name = strdup(buf_ptr(name)); - - if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { - variable_entry->var_type = g->builtin_types.entry_invalid; - } else { - variable_entry->align_bytes = get_abi_alignment(g, var_type); - } - - Scope *child_scope; - if (source_node && source_node->type == NodeTypeParamDecl) { - child_scope = create_var_scope(g, source_node, parent_scope, variable_entry); - } else { - // it's already in the decls table - child_scope = parent_scope; - } - - - variable_entry->src_is_const = is_const; - variable_entry->gen_is_const = is_const; - variable_entry->decl_node = source_node; - variable_entry->child_scope = child_scope; - - - return variable_entry; -} - -static void validate_export_var_type(CodeGen *g, ZigType* type, AstNode *source_node) { - switch (type->id) { - case ZigTypeIdMetaType: - add_node_error(g, source_node, buf_sprintf("cannot export variable of type 'type'")); - break; - default: - break; - } -} - -static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { - AstNode *source_node = tld_var->base.source_node; - AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; - - bool is_const = var_decl->is_const; - bool is_extern = var_decl->is_extern; - bool is_export = var_decl->is_export; - bool is_thread_local = var_decl->threadlocal_tok != 0; - - ZigType *explicit_type = nullptr; - if (var_decl->type) { - if (tld_var->analyzing_type) { - add_node_error(g, var_decl->type, - buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); - explicit_type = g->builtin_types.entry_invalid; - } else { - tld_var->analyzing_type = true; - ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type); - explicit_type = validate_var_type(g, var_decl, proposed_type); - } - } - - assert(!is_export || !is_extern); - - ZigValue *init_value = nullptr; - - // TODO more validation for types that can't be used for export/extern variables - ZigType *implicit_type = nullptr; - if (explicit_type != nullptr && type_is_invalid(explicit_type)) { - implicit_type = explicit_type; - } else if (var_decl->expr) { - init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, - var_decl->symbol, allow_lazy ? LazyOk : UndefOk); - assert(init_value); - implicit_type = init_value->type; - - if (implicit_type->id == ZigTypeIdUnreachable) { - add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); - implicit_type = g->builtin_types.entry_invalid; - } else if ((!is_const || is_extern) && - (implicit_type->id == ZigTypeIdComptimeFloat || - implicit_type->id == ZigTypeIdComptimeInt || - implicit_type->id == ZigTypeIdEnumLiteral)) - { - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } else if (implicit_type->id == ZigTypeIdNull) { - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } else if (implicit_type->id == ZigTypeIdMetaType && !is_const) { - add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); - implicit_type = g->builtin_types.entry_invalid; - } - assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); - } else if (!is_extern) { - add_node_error(g, source_node, buf_sprintf("variables must be initialized")); - implicit_type = g->builtin_types.entry_invalid; - } else if (explicit_type == nullptr) { - // extern variable without explicit type - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } - - ZigType *type = explicit_type ? explicit_type : implicit_type; - assert(type != nullptr); // should have been caught by the parser - - ZigValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(g, type); - - tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, - is_const, init_val, &tld_var->base, type); - tld_var->var->is_thread_local = is_thread_local; - - if (implicit_type != nullptr && type_is_invalid(implicit_type)) { - tld_var->var->var_type = g->builtin_types.entry_invalid; - } - - if (var_decl->align_expr != nullptr) { - if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { - tld_var->var->var_type = g->builtin_types.entry_invalid; - } - } - - if (var_decl->section_expr != nullptr) { - if (!analyze_const_string(g, tld_var->base.parent_scope, var_decl->section_expr, &tld_var->var->section_name)) { - tld_var->var->section_name = nullptr; - } - } - - if (is_thread_local && is_const) { - add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant")); - } - - if (is_export) { - validate_export_var_type(g, type, source_node); - add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong); - } - - if (is_extern) { - g->external_symbol_names.put_unique(tld_var->base.name, &tld_var->base); - } - - g->global_vars.append(tld_var); -} - -static void add_symbols_from_container(CodeGen *g, TldUsingNamespace *src_using_namespace, - TldUsingNamespace *dst_using_namespace, ScopeDecls* dest_decls_scope) -{ - if (src_using_namespace->base.resolution == TldResolutionUnresolved || - src_using_namespace->base.resolution == TldResolutionResolving) - { - assert(src_using_namespace->base.parent_scope->id == ScopeIdDecls); - ScopeDecls *src_decls_scope = (ScopeDecls *)src_using_namespace->base.parent_scope; - preview_use_decl(g, src_using_namespace, src_decls_scope); - if (src_using_namespace != dst_using_namespace) { - resolve_use_decl(g, src_using_namespace, src_decls_scope); - } - } - - ZigValue *use_expr = src_using_namespace->using_namespace_value; - if (type_is_invalid(use_expr->type)) { - dest_decls_scope->any_imports_failed = true; - return; - } - - dst_using_namespace->base.resolution = TldResolutionOk; - - assert(use_expr->special != ConstValSpecialRuntime); - - // The source scope for the imported symbols - ScopeDecls *src_scope = get_container_scope(use_expr->data.x_type); - // The top-level container where the symbols are defined, it's used in the - // loop below in order to exclude the ones coming from an import statement - ZigType *src_import = get_scope_import(&src_scope->base); - assert(src_import != nullptr); - - if (src_scope->any_imports_failed) { - dest_decls_scope->any_imports_failed = true; - } - - auto it = src_scope->decl_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; - - Buf *target_tld_name = entry->key; - Tld *target_tld = entry->value; - - if (target_tld->visib_mod == VisibModPrivate) { - continue; - } - - if (target_tld->import != src_import) { - continue; - } - - auto existing_entry = dest_decls_scope->decl_table.put_unique(target_tld_name, target_tld); - if (existing_entry) { - Tld *existing_decl = existing_entry->value; - if (existing_decl != target_tld) { - ErrorMsg *msg = add_node_error(g, dst_using_namespace->base.source_node, - buf_sprintf("import of '%s' overrides existing definition", - buf_ptr(target_tld_name))); - add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here")); - add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here")); - } - } - } - - for (size_t i = 0; i < src_scope->use_decls.length; i += 1) { - TldUsingNamespace *tld_using_namespace = src_scope->use_decls.at(i); - if (tld_using_namespace->base.visib_mod != VisibModPrivate) - add_symbols_from_container(g, tld_using_namespace, dst_using_namespace, dest_decls_scope); - } -} - -static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope) { - if (tld_using_namespace->base.resolution == TldResolutionOk || - tld_using_namespace->base.resolution == TldResolutionInvalid) - { - return; - } - add_symbols_from_container(g, tld_using_namespace, tld_using_namespace, dest_decls_scope); -} - -static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) { - if (using_namespace->base.resolution == TldResolutionOk || - using_namespace->base.resolution == TldResolutionInvalid || - using_namespace->using_namespace_value != nullptr) - { - return; - } - - using_namespace->base.resolution = TldResolutionResolving; - assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); - ZigValue *result = analyze_const_value(g, &dest_decls_scope->base, - using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, - nullptr, UndefBad); - using_namespace->using_namespace_value = result; - - if (type_is_invalid(result->type)) { - dest_decls_scope->any_imports_failed = true; - using_namespace->base.resolution = TldResolutionInvalid; - using_namespace->using_namespace_value = g->invalid_inst_gen->value; - return; - } - - if (!is_container(result->data.x_type)) { - add_node_error(g, using_namespace->base.source_node, - buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name))); - dest_decls_scope->any_imports_failed = true; - using_namespace->base.resolution = TldResolutionInvalid; - using_namespace->using_namespace_value = g->invalid_inst_gen->value; - return; - } -} - -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) { - bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy; - if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy) - return; - - tld->resolution = TldResolutionResolving; - update_progress_display(g); - - switch (tld->id) { - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - if (want_resolve_lazy) { - ir_resolve_lazy(g, source_node, tld_var->var->const_value); - } else { - resolve_decl_var(g, tld_var, allow_lazy); - } - tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk; - break; - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - resolve_decl_fn(g, tld_fn); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdContainer: { - TldContainer *tld_container = (TldContainer *)tld; - resolve_decl_container(g, tld_container); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdCompTime: { - TldCompTime *tld_comptime = (TldCompTime *)tld; - resolve_decl_comptime(g, tld_comptime); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdUsingNamespace: { - TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; - assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); - ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; - preview_use_decl(g, tld_using_namespace, dest_decls_scope); - resolve_use_decl(g, tld_using_namespace, dest_decls_scope); - - tld->resolution = TldResolutionOk; - break; - } - } -} - -void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope) { - // resolve all the using_namespace decls - for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) { - TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i); - if (tld_using_namespace->base.resolution == TldResolutionUnresolved) { - preview_use_decl(g, tld_using_namespace, decls_scope); - resolve_use_decl(g, tld_using_namespace, decls_scope); - } - } - -} - -Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { - resolve_container_usingnamespace_decls(g, decls_scope); - auto entry = decls_scope->decl_table.maybe_get(name); - return (entry == nullptr) ? nullptr : entry->value; -} - -Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { - while (scope) { - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - - Tld *result = find_container_decl(g, decls_scope, name); - if (result != nullptr) - return result; - } - scope = scope->parent; - } - return nullptr; -} - -ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name, ScopeFnDef **crossed_fndef_scope) { - ScopeFnDef *my_crossed_fndef_scope = nullptr; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (buf_eql_str(name, var_scope->var->name)) { - if (crossed_fndef_scope != nullptr) - *crossed_fndef_scope = my_crossed_fndef_scope; - return var_scope->var; - } - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - auto entry = decls_scope->decl_table.maybe_get(name); - if (entry) { - Tld *tld = entry->value; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - if (tld_var->var) { - if (crossed_fndef_scope != nullptr) - *crossed_fndef_scope = nullptr; - return tld_var->var; - } - } - } - } else if (scope->id == ScopeIdFnDef) { - my_crossed_fndef_scope = (ScopeFnDef *)scope; - } - scope = scope->parent; - } - - return nullptr; -} - -ZigFn *scope_fn_entry(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdFnDef) { - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - return fn_scope->fn_entry; - } - scope = scope->parent; - } - return nullptr; -} - -ZigPackage *scope_package(Scope *scope) { - ZigType *import = get_scope_import(scope); - assert(is_top_level_struct(import)); - return import->data.structure.root_struct->package; -} - -TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) { - assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.src_field_count == 0) - return nullptr; - auto entry = enum_type->data.enumeration.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; -} - -TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) { - assert(type_entry->id == ZigTypeIdStruct); - if (type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) { - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (buf_eql_buf(field->name, name)) - return field; - } - return nullptr; - } else { - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - if (type_entry->data.structure.src_field_count == 0) - return nullptr; - auto entry = type_entry->data.structure.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; - } -} - -TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name) { - assert(type_entry->id == ZigTypeIdUnion); - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - if (type_entry->data.unionation.src_field_count == 0) - return nullptr; - auto entry = type_entry->data.unionation.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; -} - -TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) { - assert(type_entry->id == ZigTypeIdUnion); - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { - TypeUnionField *field = &type_entry->data.unionation.fields[i]; - if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) { - return field; - } - } - return nullptr; -} - -TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { - assert(type_is_resolved(enum_type, ResolveStatusZeroBitsKnown)); - for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *field = &enum_type->data.enumeration.fields[i]; - if (bigint_cmp(&field->value, tag) == CmpEQ) { - return field; - } - } - return nullptr; -} - - -bool is_container(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.special != StructSpecialSlice; - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdOpaque: - return true; - case ZigTypeIdPointer: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return false; - } - zig_unreachable(); -} - -bool is_ref(ZigType *type_entry) { - return type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.ptr_len == PtrLenSingle; -} - -bool is_array_ref(ZigType *type_entry) { - ZigType *array = is_ref(type_entry) ? - type_entry->data.pointer.child_type : type_entry; - return array->id == ZigTypeIdArray; -} - -bool is_container_ref(ZigType *parent_ty) { - ZigType *ty = is_ref(parent_ty) ? parent_ty->data.pointer.child_type : parent_ty; - return is_slice(ty) || is_container(ty); -} - -ZigType *container_ref_type(ZigType *type_entry) { - assert(is_container_ref(type_entry)); - return is_ref(type_entry) ? - type_entry->data.pointer.child_type : type_entry; -} - -ZigType *get_src_ptr_type(ZigType *type) { - if (type->id == ZigTypeIdPointer) return type; - if (type->id == ZigTypeIdFn) return type; - if (type->id == ZigTypeIdAnyFrame) return type; - if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) { - return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; - } - if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; - if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type; - } - return nullptr; -} - -Error get_codegen_ptr_type(CodeGen *g, ZigType *type, ZigType **result) { - Error err; - - ZigType *ty = get_src_ptr_type(type); - if (ty == nullptr) { - *result = nullptr; - return ErrorNone; - } - - bool has_bits; - if ((err = type_has_bits2(g, ty, &has_bits))) return err; - if (!has_bits) { - *result = nullptr; - return ErrorNone; - } - - *result = ty; - return ErrorNone; -} - -ZigType *get_codegen_ptr_type_bail(CodeGen *g, ZigType *type) { - Error err; - ZigType *result; - if ((err = get_codegen_ptr_type(g, type, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -bool type_is_nonnull_ptr(CodeGen *g, ZigType *type) { - Error err; - bool result; - if ((err = type_is_nonnull_ptr2(g, type, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) { - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, type, &ptr_type))) return err; - *result = ptr_type == type && !ptr_allows_addr_zero(type); - return ErrorNone; -} - -uint32_t get_async_frame_align_bytes(CodeGen *g) { - // Due to how the frame structure is built the minimum alignment is the one - // of a usize (or pointer). - // label (grep this): [fn_frame_struct_layout] - return max(g->builtin_types.entry_usize->abi_align, target_fn_align(g->zig_target)); -} - -uint32_t get_ptr_align(CodeGen *g, ZigType *type) { - ZigType *ptr_type; - if (type->id == ZigTypeIdStruct) { - assert(type->data.structure.special == StructSpecialSlice); - TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(g, ptr_field); - } else { - ptr_type = get_src_ptr_type(type); - } - if (ptr_type->id == ZigTypeIdPointer) { - return (ptr_type->data.pointer.explicit_alignment == 0) ? - get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; - } else if (ptr_type->id == ZigTypeIdFn) { - return (ptr_type->data.fn.fn_type_id.alignment == 0) ? - target_fn_ptr_align(g->zig_target) : ptr_type->data.fn.fn_type_id.alignment; - } else if (ptr_type->id == ZigTypeIdAnyFrame) { - return get_async_frame_align_bytes(g); - } else { - zig_unreachable(); - } -} - -bool get_ptr_const(CodeGen *g, ZigType *type) { - ZigType *ptr_type; - if (type->id == ZigTypeIdStruct) { - assert(type->data.structure.special == StructSpecialSlice); - TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(g, ptr_field); - } else { - ptr_type = get_src_ptr_type(type); - } - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.is_const; - } else if (ptr_type->id == ZigTypeIdFn) { - return true; - } else if (ptr_type->id == ZigTypeIdAnyFrame) { - return true; - } else { - zig_unreachable(); - } -} - -AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index) { - if (fn_entry->param_source_nodes) - return fn_entry->param_source_nodes[index]; - else if (fn_entry->proto_node) - return fn_entry->proto_node->data.fn_proto.params.at(index); - else - return nullptr; -} - -static Error define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { - Error err; - ZigType *fn_type = fn_table_entry->type_entry; - assert(!fn_type->data.fn.is_generic); - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; - AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); - Buf *param_name; - bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; - if (param_decl_node && !is_var_args) { - param_name = param_decl_node->data.param_decl.name; - } else { - param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } - if (param_name == nullptr) { - continue; - } - - ZigType *param_type = param_info->type; - if ((err = type_resolve(g, param_type, ResolveStatusSizeKnown))) { - return err; - } - - bool is_noalias = param_info->is_noalias; - if (is_noalias) { - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, param_type, &ptr_type))) return err; - if (ptr_type == nullptr) { - add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter")); - } - } - - ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_name, true, create_const_runtime(g, param_type), nullptr, param_type); - var->src_arg_index = i; - fn_table_entry->child_scope = var->child_scope; - var->shadowable = var->shadowable || is_var_args; - - if (type_has_bits(g, param_type)) { - fn_table_entry->variable_list.append(var); - } - } - - return ErrorNone; -} - -bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node) { - assert(err_set_type->id == ZigTypeIdErrorSet); - ZigFn *infer_fn = err_set_type->data.error_set.infer_fn; - if (infer_fn != nullptr && err_set_type->data.error_set.incomplete) { - if (infer_fn->anal_state == FnAnalStateInvalid) { - return false; - } else if (infer_fn->anal_state == FnAnalStateReady) { - analyze_fn_body(g, infer_fn); - if (infer_fn->anal_state == FnAnalStateInvalid || - err_set_type->data.error_set.incomplete) - { - assert(g->errors.length != 0); - return false; - } - } else { - add_node_error(g, source_node, - buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet", - buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name))); - return false; - } - } - return true; -} - -static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { - ZigType *frame_type = get_fn_frame_type(g, fn); - Error err; - if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { - if (g->trace_err != nullptr && frame_type->data.frame.resolve_loop_src_node != nullptr && - !frame_type->data.frame.reported_loop_err) - { - frame_type->data.frame.reported_loop_err = true; - g->trace_err = add_error_note(g, g->trace_err, frame_type->data.frame.resolve_loop_src_node, - buf_sprintf("when analyzing type '%s' here", buf_ptr(&frame_type->name))); - } - fn->anal_state = FnAnalStateInvalid; - return; - } -} - -bool fn_is_async(ZigFn *fn) { - assert(fn->inferred_async_node != nullptr); - assert(fn->inferred_async_node != inferred_async_checking); - return fn->inferred_async_node != inferred_async_none; -} - -void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { - assert(fn->inferred_async_node != nullptr); - assert(fn->inferred_async_node != inferred_async_checking); - assert(fn->inferred_async_node != inferred_async_none); - if (fn->inferred_async_fn != nullptr) { - ErrorMsg *new_msg; - if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { - new_msg = add_error_note(g, msg, fn->inferred_async_node, - buf_create_from_str("await here is a suspend point")); - } else { - new_msg = add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("async function call here")); - } - return add_async_error_notes(g, new_msg, fn->inferred_async_fn); - } else if (fn->inferred_async_node->type == NodeTypeFnProto) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("async calling convention here")); - } else if (fn->inferred_async_node->type == NodeTypeSuspend) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("suspends here")); - } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("await here is a suspend point")); - } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr && - fn->inferred_async_node->data.fn_call_expr.modifier == CallModifierBuiltin) - { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("@frame() causes function to be async")); - } else { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("suspends here")); - } -} - -// ErrorNone - not async -// ErrorIsAsync - yes async -// ErrorSemanticAnalyzeFail - compile error emitted result is invalid -static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node, - bool must_not_be_async, CallModifier modifier) -{ - if (modifier == CallModifierNoSuspend) - return ErrorNone; - bool callee_is_async = false; - switch (callee->type_entry->data.fn.fn_type_id.cc) { - case CallingConventionUnspecified: - break; - case CallingConventionAsync: - callee_is_async = true; - break; - default: - return ErrorNone; - } - if (!callee_is_async) { - if (callee->anal_state == FnAnalStateReady) { - analyze_fn_body(g, callee); - if (callee->anal_state == FnAnalStateInvalid) { - return ErrorSemanticAnalyzeFail; - } - } - if (callee->anal_state == FnAnalStateComplete) { - analyze_fn_async(g, callee, true); - if (callee->anal_state == FnAnalStateInvalid) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, call_node, - buf_sprintf("while checking if '%s' is async", buf_ptr(&fn->symbol_name))); - } - return ErrorSemanticAnalyzeFail; - } - callee_is_async = fn_is_async(callee); - } else { - // If it's already been determined, use that value. Otherwise - // assume non-async, emit an error later if it turned out to be async. - if (callee->inferred_async_node == nullptr || - callee->inferred_async_node == inferred_async_checking) - { - callee->assumed_non_async = call_node; - callee_is_async = false; - } else { - callee_is_async = callee->inferred_async_node != inferred_async_none; - } - } - } - if (callee_is_async) { - bool bad_recursion = (fn->inferred_async_node == inferred_async_none); - fn->inferred_async_node = call_node; - fn->inferred_async_fn = callee; - if (must_not_be_async) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("function with calling convention '%s' cannot be async", - calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc))); - add_async_error_notes(g, msg, fn); - return ErrorSemanticAnalyzeFail; - } - if (bad_recursion) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("recursive function cannot be async")); - add_async_error_notes(g, msg, fn); - return ErrorSemanticAnalyzeFail; - } - if (fn->assumed_non_async != nullptr) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("unable to infer whether '%s' should be async", - buf_ptr(&fn->symbol_name))); - add_error_note(g, msg, fn->assumed_non_async, - buf_sprintf("assumed to be non-async here")); - add_async_error_notes(g, msg, fn); - fn->anal_state = FnAnalStateInvalid; - return ErrorSemanticAnalyzeFail; - } - return ErrorIsAsync; - } - return ErrorNone; -} - -// This function resolves functions being inferred async. -static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { - if (fn->inferred_async_node == inferred_async_checking) { - // TODO call graph cycle detected, disallow the recursion - fn->inferred_async_node = inferred_async_none; - return; - } - if (fn->inferred_async_node == inferred_async_none) { - return; - } - if (fn->inferred_async_node != nullptr) { - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - } - fn->inferred_async_node = inferred_async_checking; - - bool must_not_be_async = false; - if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) { - must_not_be_async = true; - fn->inferred_async_node = inferred_async_none; - } - - for (size_t i = 0; i < fn->call_list.length; i += 1) { - Stage1AirInstCall *call = fn->call_list.at(i); - if (call->fn_entry == nullptr) { - // TODO function pointer call here, could be anything - continue; - } - switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async, - call->modifier)) - { - case ErrorSemanticAnalyzeFail: - fn->anal_state = FnAnalStateInvalid; - return; - case ErrorNone: - continue; - case ErrorIsAsync: - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - default: - zig_unreachable(); - } - } - for (size_t i = 0; i < fn->await_list.length; i += 1) { - Stage1AirInstAwait *await = fn->await_list.at(i); - if (await->is_nosuspend) continue; - switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async, - CallModifierNone)) - { - case ErrorSemanticAnalyzeFail: - fn->anal_state = FnAnalStateInvalid; - return; - case ErrorNone: - continue; - case ErrorIsAsync: - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - default: - zig_unreachable(); - } - } - fn->inferred_async_node = inferred_async_none; -} - -static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { - ZigType *fn_type = fn->type_entry; - assert(!fn_type->data.fn.is_generic); - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - - if (fn->analyzed_executable.begin_scope == nullptr) { - fn->analyzed_executable.begin_scope = &fn->def_scope->base; - } - if (fn->analyzed_executable.source_node == nullptr) { - fn->analyzed_executable.source_node = fn->body_node; - } - size_t backward_branch_count = 0; - size_t backward_branch_quota = max(fn->branch_quota, default_backward_branch_quota); - ZigType *block_return_type = ir_analyze(g, fn->stage1_zir, &fn->analyzed_executable, - &backward_branch_count, &backward_branch_quota, - fn_type_id->return_type, return_type_node, nullptr, fn); - fn->src_implicit_return_type = block_return_type; - - if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) { - assert(g->errors.length > 0); - fn->anal_state = FnAnalStateInvalid; - return; - } - - if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) { - ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; - if (return_err_set_type->data.error_set.infer_fn != nullptr && - return_err_set_type->data.error_set.incomplete) - { - // The inferred error set type is null if the function doesn't - // return any error - ZigType *inferred_err_set_type = nullptr; - - if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) { - inferred_err_set_type = fn->src_implicit_return_type; - } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) { - inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type; - } - - if (inferred_err_set_type != nullptr) { - if (inferred_err_set_type->data.error_set.infer_fn != nullptr && - inferred_err_set_type->data.error_set.incomplete) - { - if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) { - fn->anal_state = FnAnalStateInvalid; - return; - } - } - - return_err_set_type->data.error_set.incomplete = false; - if (type_is_global_error_set(inferred_err_set_type)) { - return_err_set_type->data.error_set.err_count = UINT32_MAX; - } else { - return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; - if (inferred_err_set_type->data.error_set.err_count > 0) { - return_err_set_type->data.error_set.errors = heap::c_allocator.allocate(inferred_err_set_type->data.error_set.err_count); - for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) { - return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i]; - } - } - } - } else { - return_err_set_type->data.error_set.incomplete = false; - return_err_set_type->data.error_set.err_count = 0; - } - } - } - - CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc; - if (cc != CallingConventionUnspecified && cc != CallingConventionAsync && - fn->inferred_async_node != nullptr && - fn->inferred_async_node != inferred_async_checking && - fn->inferred_async_node != inferred_async_none) - { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("function with calling convention '%s' cannot be async", - calling_convention_name(cc))); - add_async_error_notes(g, msg, fn); - fn->anal_state = FnAnalStateInvalid; - } - - if (g->verbose_ir) { - fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name)); - ir_print_gen(g, stderr, &fn->analyzed_executable, 4); - fprintf(stderr, "}\n"); - } - fn->anal_state = FnAnalStateComplete; -} - -static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { - assert(fn_table_entry->anal_state != FnAnalStateProbing); - if (fn_table_entry->anal_state != FnAnalStateReady) - return; - - fn_table_entry->anal_state = FnAnalStateProbing; - update_progress_display(g); - - AstNode *return_type_node = (fn_table_entry->proto_node != nullptr) ? - fn_table_entry->proto_node->data.fn_proto.return_type : fn_table_entry->fndef_scope->base.source_node; - - assert(fn_table_entry->fndef_scope); - if (!fn_table_entry->child_scope) - fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base; - - if (define_local_param_variables(g, fn_table_entry) != ErrorNone) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - ZigType *fn_type = fn_table_entry->type_entry; - assert(!fn_type->data.fn.is_generic); - - if (!stage1_astgen_fn(g, fn_table_entry)) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - if (fn_table_entry->stage1_zir->first_err_trace_msg != nullptr) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - if (g->verbose_ir) { - fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); - ir_print_src(g, stderr, fn_table_entry->stage1_zir, 4); - fprintf(stderr, "}\n"); - } - - analyze_fn_ir(g, fn_table_entry, return_type_node); -} - -ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code, - SourceKind source_kind) -{ - Tokenization tokenization = {0}; - tokenize(buf_ptr(source_code), &tokenization); - - if (tokenization.err) { - ErrorMsg *err = err_msg_create_with_offset(resolved_path, tokenization.err_byte_offset, - buf_ptr(source_code), tokenization.err); - - print_err_msg(err, g->err_color); - exit(1); - } - - Buf *src_dirname = buf_alloc(); - Buf *src_basename = buf_alloc(); - os_path_split(resolved_path, src_dirname, src_basename); - - Buf noextname = BUF_INIT; - os_path_extname(resolved_path, &noextname, nullptr); - - Buf *pkg_root_src_dir = &package->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - - Buf *namespace_name = buf_create_from_buf(&package->pkg_path); - if (source_kind == SourceKindNonRoot) { - assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir)); - if (buf_len(namespace_name) != 0) { - buf_append_char(namespace_name, NAMESPACE_SEP_CHAR); - } - // The namespace components are obtained from the relative path to the - // source directory - if (buf_len(&noextname) > buf_len(&resolved_root_src_dir)) { - // Skip the trailing separator - buf_append_mem(namespace_name, - buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1, - buf_len(&noextname) - buf_len(&resolved_root_src_dir) - 1); - } - buf_replace(namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR); - } - Buf *bare_name = buf_alloc(); - os_path_extname(src_basename, bare_name, nullptr); - - RootStruct *root_struct = heap::c_allocator.create(); - root_struct->package = package; - root_struct->source_code = source_code; - root_struct->path = resolved_path; - root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); - - assert(tokenization.ids.length == tokenization.locs.length); - size_t token_count = tokenization.ids.length; - root_struct->token_count = token_count; - root_struct->token_ids = g->pass1_arena->allocate(token_count); - memcpy(root_struct->token_ids, tokenization.ids.items, token_count * sizeof(TokenId)); - root_struct->token_locs = g->pass1_arena->allocate(token_count); - memcpy(root_struct->token_locs, tokenization.locs.items, token_count * sizeof(TokenLoc)); - - tokenization.ids.deinit(); - tokenization.locs.deinit(); - - ZigType *import_entry = get_root_container_type(g, buf_ptr(namespace_name), bare_name, root_struct); - if (source_kind == SourceKindRoot) { - assert(g->root_import == nullptr); - g->root_import = import_entry; - } - g->import_table.put(resolved_path, import_entry); - - AstNode *root_node = ast_parse(source_code, import_entry, g->err_color); - assert(root_node != nullptr); - assert(root_node->type == NodeTypeContainerDecl); - import_entry->data.structure.decl_node = root_node; - import_entry->data.structure.decls_scope->base.source_node = root_node; - - for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { - AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); - scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl); - } - - TldContainer *tld_container = heap::c_allocator.create(); - init_tld(&tld_container->base, TldIdContainer, namespace_name, VisibModPub, root_node, nullptr); - tld_container->type_entry = import_entry; - tld_container->decls_scope = import_entry->data.structure.decls_scope; - g->resolve_queue.append(&tld_container->base); - - return import_entry; -} - -void semantic_analyze(CodeGen *g) { - while (g->resolve_queue_index < g->resolve_queue.length || - g->fn_defs_index < g->fn_defs.length) - { - for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { - Tld *tld = g->resolve_queue.at(g->resolve_queue_index); - g->trace_err = nullptr; - AstNode *source_node = nullptr; - resolve_top_level_decl(g, tld, source_node, false); - } - - for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); - g->trace_err = nullptr; - analyze_fn_body(g, fn_entry); - } - } - - if (g->errors.length != 0) { - return; - } - - // second pass over functions for detecting async - for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn = g->fn_defs.at(g->fn_defs_index); - g->trace_err = nullptr; - analyze_fn_async(g, fn, true); - if (fn->anal_state == FnAnalStateInvalid) - continue; - if (fn_is_async(fn) && fn->non_async_node != nullptr) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name))); - add_error_note(g, msg, fn->non_async_node, - buf_sprintf("required to be non-async here")); - add_async_error_notes(g, msg, fn); - } - } -} - -ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { - assert(size_in_bits <= 65535); - TypeId type_id = {}; - type_id.id = ZigTypeIdInt; - type_id.data.integer.is_signed = is_signed; - type_id.data.integer.bit_count = size_in_bits; - - { - auto entry = g->type_table.maybe_get(type_id); - if (entry) - return entry->value; - } - - ZigType *new_entry = make_int_type(g, is_signed, size_in_bits); - g->type_table.put(type_id, new_entry); - return new_entry; -} - -Error is_valid_vector_elem_type(CodeGen *g, ZigType *elem_type, bool *result) { - if (elem_type->id == ZigTypeIdInt || - elem_type->id == ZigTypeIdFloat || - elem_type->id == ZigTypeIdBool) - { - *result = true; - return ErrorNone; - } - - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, elem_type, &ptr_type))) return err; - if (ptr_type != nullptr) { - *result = true; - return ErrorNone; - } - - *result = false; - return ErrorNone; -} - -ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { - Error err; - - bool valid_vector_elem; - if ((err = is_valid_vector_elem_type(g, elem_type, &valid_vector_elem))) { - codegen_report_errors_and_exit(g); - } - assert(valid_vector_elem); - - TypeId type_id = {}; - type_id.id = ZigTypeIdVector; - type_id.data.vector.len = len; - type_id.data.vector.elem_type = elem_type; - - { - auto entry = g->type_table.maybe_get(type_id); - if (entry) - return entry->value; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdVector); - if ((len != 0) && type_has_bits(g, elem_type)) { - // Vectors can only be ints, floats, bools, or pointers. ints (inc. bools) and floats have trivially resolvable - // llvm type refs. pointers we will use usize instead. - LLVMTypeRef example_vector_llvm_type; - if (elem_type->id == ZigTypeIdPointer) { - example_vector_llvm_type = LLVMVectorType(g->builtin_types.entry_usize->llvm_type, len); - } else { - example_vector_llvm_type = LLVMVectorType(elem_type->llvm_type, len); - } - assert(example_vector_llvm_type != nullptr); - entry->size_in_bits = elem_type->size_in_bits * len; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, example_vector_llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, example_vector_llvm_type); - } - entry->data.vector.len = len; - entry->data.vector.elem_type = elem_type; - entry->data.vector.padding = 0; - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { - return &g->builtin_types.entry_c_int[c_int_type]; -} - -ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type) { - return *get_c_int_type_ptr(g, c_int_type); -} - -bool handle_is_ptr(CodeGen *g, ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdEnum: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return false; - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdFnFrame: - return type_has_bits(g, type_entry); - case ZigTypeIdErrorUnion: - return type_has_bits(g, type_entry->data.error_union.payload_type); - case ZigTypeIdOptional: - return type_has_bits(g, type_entry->data.maybe.child_type) && - !type_is_nonnull_ptr(g, type_entry->data.maybe.child_type) && - type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet; - case ZigTypeIdUnion: - return type_has_bits(g, type_entry) && type_entry->data.unionation.gen_field_count != 0; - - } - zig_unreachable(); -} - -static const uint32_t HASH_INIT = 0x811c9dc5U; - -template -static uint32_t hash_combine(uint32_t hash, const T *value, size_t count = 1) { - // Simple FNV32 hash - size_t len = sizeof(T) * count; - const unsigned char *char_bytes = (const unsigned char*)value; - for (size_t c = 0; c < len; ++c) { - hash ^= char_bytes[c]; - hash *= 0x01000193U; - } - return hash; -} - -static uint32_t hash_combine_bigint(uint32_t hash, const BigInt *value) { - return hash_combine(hash, bigint_ptr(value), value->digit_count); -} - -static uint32_t hash_combine_buf(uint32_t hash, const Buf *buf) { - return hash_combine(hash, buf_ptr(buf), buf_len(buf)); -} - -uint32_t fn_table_entry_hash(ZigFn* value) { - return hash_combine(HASH_INIT, &value); -} - -bool fn_table_entry_eql(ZigFn *a, ZigFn *b) { - return a == b; -} - -uint32_t fn_type_id_hash(FnTypeId *id) { - uint32_t hash = HASH_INIT; - hash = hash_combine(hash, &id->cc); - hash = hash_combine(hash, &id->is_var_args); - hash = hash_combine(hash, &id->return_type); - hash = hash_combine(hash, &id->alignment); - for (size_t i = 0; i < id->param_count; i += 1) { - FnTypeParamInfo *info = &id->param_info[i]; - hash = hash_combine(hash, &info->is_noalias); - hash = hash_combine(hash, &info->type); - } - return hash; -} - -bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { - if (a->cc != b->cc || - a->return_type != b->return_type || - a->is_var_args != b->is_var_args || - a->param_count != b->param_count || - a->alignment != b->alignment) - { - return false; - } - for (size_t i = 0; i < a->param_count; i += 1) { - FnTypeParamInfo *a_param_info = &a->param_info[i]; - FnTypeParamInfo *b_param_info = &b->param_info[i]; - - if (a_param_info->type != b_param_info->type || - a_param_info->is_noalias != b_param_info->is_noalias) - { - return false; - } - } - return true; -} - -static uint32_t hash_combine_const_val_error_set(uint32_t hash_val, ZigValue *const_val) { - assert(const_val->data.x_err_set != nullptr); - return hash_combine(hash_val, &const_val->data.x_err_set->value); -} - -static uint32_t hash_combine_const_val_ptr(uint32_t hash_val, ZigValue *const_val) { - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.special); - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.ref.pointee); - return hash_val; - case ConstPtrSpecialBaseArray: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); - return hash_val; - case ConstPtrSpecialSubArray: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); - return hash_val; - case ConstPtrSpecialBaseStruct: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_struct.struct_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_struct.field_index); - return hash_val; - case ConstPtrSpecialBaseErrorUnionCode: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_err_union_code.err_union_val); - return hash_val; - case ConstPtrSpecialBaseErrorUnionPayload: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_err_union_payload.err_union_val); - return hash_val; - case ConstPtrSpecialBaseOptionalPayload: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_optional_payload.optional_val); - return hash_val; - case ConstPtrSpecialHardCodedAddr: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.hard_coded_addr.addr); - return hash_val; - case ConstPtrSpecialFunction: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); - return hash_val; - case ConstPtrSpecialDiscard: - case ConstPtrSpecialNull: - // No fields to hash - return hash_val; - } - zig_unreachable(); -} - -static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val); -static uint32_t hash_combine_const_val_array(uint32_t hash_val, ZigValue *array, size_t len) { - if (array->data.x_array.special == ConstArraySpecialUndef) { - char undef_tag = 56; - return hash_combine(hash_val, &undef_tag); - } else if (array->data.x_array.special == ConstArraySpecialBuf) { - // Hash in a way that is compatible with standard byte arrays - // If any of these asserts fails, the if after this needs to be modified - // to handle the new type in SpecialBuf. - assert(array->type->data.array.child_type->id == ZigTypeIdInt); - assert(array->type->data.array.child_type->data.integral.bit_count == 8); - assert(array->type->data.array.child_type->data.integral.is_signed == false); - const char *buf_pos = buf_ptr(array->data.x_array.data.s_buf); - const char *buf_end = buf_pos + buf_len(array->data.x_array.data.s_buf); - while (buf_pos < buf_end) { - hash_val = hash_combine(hash_val, buf_pos); - buf_pos++; - } - return hash_val; - } else if (array->type->data.array.child_type->id == ZigTypeIdInt && - array->type->data.array.child_type->data.integral.bit_count == 8 && - array->type->data.array.child_type->data.integral.is_signed == false) { - // If the type is u8, we hash it as if it's a ConstArraySpecialBuf, - // to maintain compatibility. - ZigValue *elems = array->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; i += 1) { - ZigValue *value = &elems[i]; - assert(value->type == array->type->data.array.child_type); - // N.B. Using char here instead of uint8_t to match the const char* - // returned by buf_ptr. - const char byte_value = (char) bigint_as_u8(&value->data.x_bigint); - hash_val = hash_combine(hash_val, &byte_value); - } - return hash_val; - } else { - ZigValue *elems = array->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; i += 1) { - hash_val = hash_combine_const_val(hash_val, &elems[i]); - } - return hash_val; - } -} -static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { - hash_val = hash_combine(hash_val, &const_val->special); - if (const_val->special == ConstValSpecialUndef) { - return hash_val; - } - assert(const_val->special == ConstValSpecialStatic); - hash_val = hash_combine(hash_val, &const_val->type->id); - switch (const_val->type->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdBool: - return hash_combine(hash_val, &const_val->data.x_bool); - case ZigTypeIdMetaType: - return hash_combine(hash_val, &const_val->data.x_type); - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - return hash_combine_bigint(hash_val, &const_val->data.x_bigint); - case ZigTypeIdEnumLiteral: - return hash_combine_buf(hash_val, const_val->data.x_enum_literal); - case ZigTypeIdEnum: - return hash_combine_bigint(hash_val, &const_val->data.x_enum_tag); - case ZigTypeIdFloat: - hash_val = hash_combine(hash_val, &const_val->type->data.floating.bit_count); - switch (const_val->type->data.floating.bit_count) { - case 16: return hash_combine(hash_val, &const_val->data.x_f16); - case 32: return hash_combine(hash_val, &const_val->data.x_f32); - case 64: return hash_combine(hash_val, &const_val->data.x_f64); - case 80: - hash_val = hash_combine(hash_val, &const_val->data.x_f80.signExp); - return hash_combine(hash_val, &const_val->data.x_f80.signif); - case 128: return hash_combine(hash_val, &const_val->data.x_f128); - default: zig_unreachable(); - } - case ZigTypeIdComptimeFloat: - return hash_combine(hash_val, &const_val->data.x_bigfloat.value); - case ZigTypeIdFn: - assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); - return hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); - case ZigTypeIdPointer: - return hash_combine_const_val_ptr(hash_val, const_val); - case ZigTypeIdVoid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - return hash_val; - case ZigTypeIdArray: - return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.array.len); - case ZigTypeIdStruct: { - size_t field_count = const_val->type->data.structure.src_field_count; - for (size_t i = 0; i < field_count; i += 1) { - if (const_val->type->data.structure.fields[i]->is_comptime) { - // The values of comptime struct fields are part of the - // type, not the value, so they do not participate in equality - // or hash of comptime values. - continue; - } - ZigValue *field = const_val->data.x_struct.fields[i]; - hash_val = hash_combine_const_val(hash_val, field); - } - return hash_val; - } - case ZigTypeIdUnion: { - ConstUnionValue *union_value = &const_val->data.x_union; - hash_val = hash_combine_bigint(hash_val, &union_value->tag); - return hash_combine_const_val(hash_val, union_value->payload); - } - case ZigTypeIdOptional: - if (get_src_ptr_type(const_val->type) != nullptr) { - char tag = 1; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val_ptr(hash_val, const_val); - } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { - char tag = 2; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val_error_set(hash_val, const_val); - } else if (const_val->data.x_optional) { - char tag = 3; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val(hash_val, const_val->data.x_optional); - } else { - char tag = 4; - hash_val = hash_combine(hash_val, &tag); - return hash_val; - } - case ZigTypeIdErrorUnion: { - bool is_err = const_val->data.x_err_union.error_set->data.x_err_set != nullptr; - hash_val = hash_combine(hash_val, &is_err); - if (is_err) { - hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.error_set); - } else { - hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.payload); - } - return hash_val; - } - case ZigTypeIdErrorSet: - return hash_combine_const_val_error_set(hash_val, const_val); - case ZigTypeIdVector: - return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.vector.len); - case ZigTypeIdFnFrame: - // TODO better hashing algorithm - return hash_val; - case ZigTypeIdAnyFrame: - // TODO better hashing algorithm - return hash_val; - case ZigTypeIdBoundFn: { - assert(const_val->data.x_bound_fn.fn != nullptr); - return hash_combine(hash_val, &const_val->data.x_bound_fn.fn); - } - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - } - zig_unreachable(); -} - -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { - uint32_t result = HASH_INIT; - result = hash_combine(result, &id->fn_entry); - for (size_t i = 0; i < id->param_count; i += 1) { - ZigValue *generic_param = &id->params[i]; - if (generic_param->special != ConstValSpecialRuntime) { - result = hash_combine_const_val(result, generic_param); - result = hash_combine(result, &generic_param->type); - } - } - return result; -} - -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { - assert(a->fn_entry); - if (a->fn_entry != b->fn_entry) return false; - if (a->param_count != b->param_count) return false; - for (size_t i = 0; i < a->param_count; i += 1) { - ZigValue *a_val = &a->params[i]; - ZigValue *b_val = &b->params[i]; - if (a_val->type != b_val->type) return false; - if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) { - assert(a_val->special == ConstValSpecialStatic); - assert(b_val->special == ConstValSpecialStatic); - if (!const_values_equal(a->codegen, a_val, b_val)) { - return false; - } - } else { - assert(a_val->special == ConstValSpecialRuntime && b_val->special == ConstValSpecialRuntime); - } - } - return true; -} - -static bool can_mutate_comptime_var_state(ZigValue *value) { - assert(value != nullptr); - if (value->special == ConstValSpecialUndef) - return false; - - if (value->special == ConstValSpecialLazy) { - // No lazy value has side effects. - // Use a switch here to get a compile error whenever a new kind of lazy - // value is added. - switch (value->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdOptType: - case LazyValueIdSliceType: - case LazyValueIdFnType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - case LazyValueIdTypeInfoDecls: - return false; - } - } - - switch (value->type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdVector: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdFn: - case ZigTypeIdOpaque: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return false; - - case ZigTypeIdPointer: - return value->data.x_ptr.mut == ConstPtrMutComptimeVar; - - case ZigTypeIdArray: - if (value->special == ConstValSpecialUndef) - return false; - if (value->type->data.array.len == 0) - return false; - switch (value->data.x_array.special) { - case ConstArraySpecialUndef: - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (uint32_t i = 0; i < value->type->data.array.len; i += 1) { - if (can_mutate_comptime_var_state(&value->data.x_array.data.s_none.elements[i])) - return true; - } - return false; - } - zig_unreachable(); - case ZigTypeIdStruct: - for (uint32_t i = 0; i < value->type->data.structure.src_field_count; i += 1) { - TypeStructField *type_struct_field = value->type->data.structure.fields[i]; - - ZigValue *field_value = type_struct_field->is_comptime ? - type_struct_field->init_val : - value->data.x_struct.fields[i]; - - if (can_mutate_comptime_var_state(field_value)) - return true; - } - return false; - - case ZigTypeIdOptional: - if (get_src_ptr_type(value->type) != nullptr) - return value->data.x_ptr.mut == ConstPtrMutComptimeVar; - if (value->data.x_optional == nullptr) - return false; - return can_mutate_comptime_var_state(value->data.x_optional); - - case ZigTypeIdErrorUnion: - if (value->data.x_err_union.error_set->data.x_err_set != nullptr) - return false; - assert(value->data.x_err_union.payload != nullptr); - return can_mutate_comptime_var_state(value->data.x_err_union.payload); - - case ZigTypeIdUnion: - return can_mutate_comptime_var_state(value->data.x_union.payload); - } - zig_unreachable(); -} - -bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (type_is_invalid(var_scope->var->var_type)) - return false; - if (var_scope->var->const_value->special == ConstValSpecialUndef) - return false; - if (can_mutate_comptime_var_state(var_scope->var->const_value)) - return false; - } else if (scope->id == ScopeIdFnDef) { - return true; - } else { - zig_unreachable(); - } - - scope = scope->parent; - } - zig_unreachable(); -} - -uint32_t fn_eval_hash(Scope* scope) { - uint32_t hash = HASH_INIT; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - hash = hash_combine_const_val(hash, var_scope->var->const_value); - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - hash = hash_combine(hash, &fn_scope->fn_entry); - return hash; - } else { - zig_unreachable(); - } - - scope = scope->parent; - } - zig_unreachable(); -} - -bool fn_eval_eql(Scope *a, Scope *b) { - assert(a->codegen != nullptr); - assert(b->codegen != nullptr); - while (a && b) { - if (a->id != b->id) - return false; - - if (a->id == ScopeIdVarDecl) { - ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; - ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; - if (a_var_scope->var->var_type != b_var_scope->var->var_type) - return false; - if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && - b_var_scope->var->var_type == b_var_scope->var->const_value->type) - { - if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) - return false; - } else { - zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); - } - } else if (a->id == ScopeIdFnDef) { - ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; - ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; - if (a_fn_scope->fn_entry != b_fn_scope->fn_entry) - return false; - - return true; - } else { - zig_unreachable(); - } - - a = a->parent; - b = b->parent; - } - return false; -} - -// Deprecated. Use type_has_bits2. -bool type_has_bits(CodeGen *g, ZigType *type_entry) { - Error err; - bool result; - if ((err = type_has_bits2(g, type_entry, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -// Whether the type has bits at runtime. -Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result) { - Error err; - - if (type_is_invalid(type_entry)) - return ErrorSemanticAnalyzeFail; - - if (type_entry->id == ZigTypeIdStruct && - type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) - { - *result = true; - return ErrorNone; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - - *result = type_entry->abi_size != 0; - return ErrorNone; -} - -bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id) { - ZigType *type = fn_type_id->return_type; - return !calling_convention_allows_zig_types(fn_type_id->cc) && - type->id == ZigTypeIdStruct && type->abi_size <= 16; -} - -// Whether you can infer the value based solely on the type. -OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { - assert(type_entry != nullptr); - - if (type_entry->one_possible_value != OnePossibleValueInvalid) - return type_entry->one_possible_value; - - if (type_entry->id == ZigTypeIdStruct && - type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) - { - return OnePossibleValueNo; - } - - Error err; - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return OnePossibleValueInvalid; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdOpaque: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdMetaType: - case ZigTypeIdBoundFn: - case ZigTypeIdOptional: - case ZigTypeIdFn: - case ZigTypeIdBool: - case ZigTypeIdFloat: - case ZigTypeIdErrorUnion: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return OnePossibleValueNo; - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - return OnePossibleValueYes; - case ZigTypeIdArray: - if (type_entry->data.array.len == 0) - return OnePossibleValueYes; - return type_has_one_possible_value(g, type_entry->data.array.child_type); - case ZigTypeIdStruct: - // If the recursive function call asks, then we are not one possible value. - type_entry->one_possible_value = OnePossibleValueNo; - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (field->is_comptime) { - // If this field is comptime then the field can only be one possible value - continue; - } - OnePossibleValue opv = (field->type_entry != nullptr) ? - type_has_one_possible_value(g, field->type_entry) : - type_val_resolve_has_one_possible_value(g, field->type_val); - switch (opv) { - case OnePossibleValueInvalid: - type_entry->one_possible_value = OnePossibleValueInvalid; - return OnePossibleValueInvalid; - case OnePossibleValueNo: - return OnePossibleValueNo; - case OnePossibleValueYes: - continue; - } - } - type_entry->one_possible_value = OnePossibleValueYes; - return OnePossibleValueYes; - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdVector: - return type_has_bits(g, type_entry) ? OnePossibleValueNo : OnePossibleValueYes; - case ZigTypeIdPointer: { - ZigType *elem_type = type_entry->data.pointer.child_type; - // If the recursive function call asks, then we are not one possible value. - type_entry->one_possible_value = OnePossibleValueNo; - // Now update it to be the value of the recursive call. - type_entry->one_possible_value = type_has_one_possible_value(g, elem_type); - return type_entry->one_possible_value; - } - case ZigTypeIdUnion: - if (type_entry->data.unionation.src_field_count > 1) - return OnePossibleValueNo; - TypeUnionField *only_field = &type_entry->data.unionation.fields[0]; - if (only_field->type_entry != nullptr) { - return type_has_one_possible_value(g, only_field->type_entry); - } - return type_val_resolve_has_one_possible_value(g, only_field->type_val); - } - zig_unreachable(); -} - -ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { - auto entry = g->one_possible_values.maybe_get(type_entry); - if (entry != nullptr) { - return entry->value; - } - ZigValue *result = g->pass1_arena->create(); - result->type = type_entry; - result->special = ConstValSpecialStatic; - - if (result->type->id == ZigTypeIdStruct) { - // The fields array cannot be left unpopulated - const ZigType *struct_type = result->type; - const size_t field_count = struct_type->data.structure.src_field_count; - result->data.x_struct.fields = alloc_const_vals_ptrs(g, field_count); - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, and do not need to - // be initialized. - continue; - } - ZigType *field_type = resolve_struct_field_type(g, field); - assert(field_type != nullptr); - copy_const_val(g, result->data.x_struct.fields[i], - get_the_one_possible_value(g, field_type)); - } - } else if (result->type->id == ZigTypeIdArray) { - // The elements array cannot be left unpopulated - ZigType *array_type = result->type; - ZigType *elem_type = array_type->data.array.child_type; - const size_t elem_count = array_type->data.array.len; - - result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; - copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); - } - } else if (result->type->id == ZigTypeIdUnion) { - // The payload/tag fields cannot be left unpopulated - ZigType *union_type = result->type; - assert(union_type->data.unionation.src_field_count == 1); - TypeUnionField *only_field = &union_type->data.unionation.fields[0]; - ZigType *field_type = resolve_union_field_type(g, only_field); - assert(field_type); - bigint_init_bigint(&result->data.x_union.tag, &only_field->enum_field->value); - result->data.x_union.payload = g->pass1_arena->create(); - copy_const_val(g, result->data.x_union.payload, - get_the_one_possible_value(g, field_type)); - } else if (result->type->id == ZigTypeIdPointer) { - // Make sure nobody can modify the constant value - result->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->data.x_ptr.special = ConstPtrSpecialRef; - result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); - } else if (result->type->id == ZigTypeIdEnum) { - ZigType *enum_type = result->type; - assert(enum_type->data.enumeration.src_field_count == 1); - TypeEnumField *only_field = &result->type->data.enumeration.fields[0]; - bigint_init_bigint(&result->data.x_enum_tag, &only_field->value); - } - g->one_possible_values.put(type_entry, result); - return result; -} - -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { - Error err; - if (ty == g->builtin_types.entry_anytype) { - return ReqCompTimeYes; - } - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdMetaType: - case ZigTypeIdBoundFn: - return ReqCompTimeYes; - case ZigTypeIdArray: - return type_requires_comptime(g, ty->data.array.child_type); - case ZigTypeIdStruct: - if (ty->data.structure.resolve_loop_flag_zero_bits) { - // Does a struct which contains a pointer field to itself require comptime? No. - return ReqCompTimeNo; - } - if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdUnion: - if (ty->data.unionation.resolve_loop_flag_zero_bits) { - // Does a union which contains a pointer field to itself require comptime? No. - return ReqCompTimeNo; - } - if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdOptional: - return type_requires_comptime(g, ty->data.maybe.child_type); - case ZigTypeIdErrorUnion: - return type_requires_comptime(g, ty->data.error_union.payload_type); - case ZigTypeIdPointer: - if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { - return ReqCompTimeNo; - } else { - return type_requires_comptime(g, ty->data.pointer.child_type); - } - case ZigTypeIdFn: - return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdOpaque: - case ZigTypeIdEnum: - case ZigTypeIdErrorSet: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdVector: - case ZigTypeIdFloat: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return ReqCompTimeNo; - } - zig_unreachable(); -} - -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str) { - auto entry = g->string_literals_table.maybe_get(str); - if (entry != nullptr) { - if (move_str) { - buf_destroy(str); - } - memcpy(const_val, entry->value, sizeof(ZigValue)); - return; - } - - // first we build the underlying array - ZigValue *array_val = g->pass1_arena->create(); - array_val->special = ConstValSpecialStatic; - array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), g->intern.for_zero_byte()); - array_val->data.x_array.special = ConstArraySpecialBuf; - array_val->data.x_array.data.s_buf = str; - - // then make the pointer point to it - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type_extra2(g, array_val->type, true, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.data.ref.pointee = array_val; - - g->string_literals_table.put(str, const_val); -} - -ZigValue *create_const_str_lit(CodeGen *g, Buf *str) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_str_lit(g, const_val, str, false); - return const_val; -} - -ZigValue *create_sentineled_str_lit(CodeGen *g, Buf *str, ZigValue *sentinel) { - ZigValue *array_val = create_const_str_lit(g, str)->data.x_ptr.data.ref.pointee; - return create_const_slice(g, array_val, 0, buf_len(str), true, sentinel); -} - -void init_const_bigint(ZigValue *const_val, ZigType *type, const BigInt *bigint) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_bigint(&const_val->data.x_bigint, bigint); -} - -ZigValue *create_const_bigint(CodeGen *g, ZigType *type, const BigInt *bigint) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_bigint(const_val, type, bigint); - return const_val; -} - - -void init_const_unsigned_negative(ZigValue *const_val, ZigType *type, uint64_t x, bool negative) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_unsigned(&const_val->data.x_bigint, x); - const_val->data.x_bigint.is_negative = negative; -} - -ZigValue *create_const_unsigned_negative(CodeGen *g, ZigType *type, uint64_t x, bool negative) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_unsigned_negative(const_val, type, x, negative); - return const_val; -} - -void init_const_usize(CodeGen *g, ZigValue *const_val, uint64_t x) { - return init_const_unsigned_negative(const_val, g->builtin_types.entry_usize, x, false); -} - -ZigValue *create_const_usize(CodeGen *g, uint64_t x) { - return create_const_unsigned_negative(g, g->builtin_types.entry_usize, x, false); -} - -void init_const_signed(ZigValue *const_val, ZigType *type, int64_t x) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_signed(&const_val->data.x_bigint, x); -} - -ZigValue *create_const_signed(CodeGen *g, ZigType *type, int64_t x) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_signed(const_val, type, x); - return const_val; -} - -void init_const_null(ZigValue *const_val, ZigType *type) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - const_val->data.x_optional = nullptr; -} - -ZigValue *create_const_null(CodeGen *g, ZigType *type) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_null(const_val, type); - return const_val; -} - -void init_const_fn(ZigValue *const_val, ZigFn *fn) { - const_val->special = ConstValSpecialStatic; - const_val->type = fn->type_entry; - const_val->data.x_ptr.special = ConstPtrSpecialFunction; - const_val->data.x_ptr.data.fn.fn_entry = fn; -} - -ZigValue *create_const_fn(CodeGen *g, ZigFn *fn) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_fn(const_val, fn); - return const_val; -} - -void init_const_float(ZigValue *const_val, ZigType *type, double value) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - if (type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_64(&const_val->data.x_bigfloat, value); - } else if (type->id == ZigTypeIdFloat) { - switch (type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = zig_double_to_f16(value); - break; - case 32: - const_val->data.x_f32 = value; - break; - case 64: - const_val->data.x_f64 = value; - break; - case 80: - zig_double_to_extF80M(value, &const_val->data.x_f80); - break; - case 128: - zig_double_to_f128M(value, &const_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -ZigValue *create_const_float(CodeGen *g, ZigType *type, double value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_float(const_val, type, value); - return const_val; -} - -void init_const_enum(ZigValue *const_val, ZigType *type, const BigInt *tag) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_bigint(&const_val->data.x_enum_tag, tag); -} - -ZigValue *create_const_enum(CodeGen *g, ZigType *type, const BigInt *tag) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_enum(const_val, type, tag); - return const_val; -} - - -void init_const_bool(CodeGen *g, ZigValue *const_val, bool value) { - const_val->special = ConstValSpecialStatic; - const_val->type = g->builtin_types.entry_bool; - const_val->data.x_bool = value; -} - -ZigValue *create_const_bool(CodeGen *g, bool value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_bool(g, const_val, value); - return const_val; -} - -void init_const_runtime(ZigValue *const_val, ZigType *type) { - const_val->special = ConstValSpecialRuntime; - const_val->type = type; -} - -ZigValue *create_const_runtime(CodeGen *g, ZigType *type) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_runtime(const_val, type); - return const_val; -} - -void init_const_type(CodeGen *g, ZigValue *const_val, ZigType *type_value) { - const_val->special = ConstValSpecialStatic; - const_val->type = g->builtin_types.entry_type; - const_val->data.x_type = type_value; -} - -ZigValue *create_const_type(CodeGen *g, ZigType *type_value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_type(g, const_val, type_value); - return const_val; -} - -void init_const_slice(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t start, size_t len, bool is_const, ZigValue *sentinel) -{ - assert(array_val->type->id == ZigTypeIdArray); - - ZigType *ptr_type = get_pointer_to_type_extra2(g, array_val->type->data.array.child_type, - is_const, false, PtrLenUnknown, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel); - - const_val->special = ConstValSpecialStatic; - const_val->type = get_slice_type(g, ptr_type); - const_val->data.x_struct.fields = alloc_const_vals_ptrs(g, 2); - - init_const_ptr_array(g, const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const, - PtrLenUnknown); - init_const_usize(g, const_val->data.x_struct.fields[slice_len_index], len); -} - -ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size_t len, bool is_const, ZigValue *sentinel) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_slice(g, const_val, array_val, start, len, is_const, sentinel); - return const_val; -} - -void init_const_ptr_array(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t elem_index, bool is_const, PtrLen ptr_len) -{ - assert(array_val->type->id == ZigTypeIdArray); - ZigType *child_type = array_val->type->data.array.child_type; - - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false, - ptr_len, 0, 0, 0, false); - const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - const_val->data.x_ptr.data.base_array.array_val = array_val; - const_val->data.x_ptr.data.base_array.elem_index = elem_index; -} - -ZigValue *create_const_ptr_array(CodeGen *g, ZigValue *array_val, size_t elem_index, bool is_const, - PtrLen ptr_len) -{ - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_array(g, const_val, array_val, elem_index, is_const, ptr_len); - return const_val; -} - -void init_const_ptr_ref(CodeGen *g, ZigValue *const_val, ZigValue *pointee_val, bool is_const) { - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type(g, pointee_val->type, is_const); - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.data.ref.pointee = pointee_val; -} - -ZigValue *create_const_ptr_ref(CodeGen *g, ZigValue *pointee_val, bool is_const) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_ref(g, const_val, pointee_val, is_const); - return const_val; -} - -void init_const_ptr_hard_coded_addr(CodeGen *g, ZigValue *const_val, ZigType *pointee_type, - size_t addr, bool is_const) -{ - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type(g, pointee_type, is_const); - const_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - const_val->data.x_ptr.data.hard_coded_addr.addr = addr; -} - -ZigValue *create_const_ptr_hard_coded_addr(CodeGen *g, ZigType *pointee_type, - size_t addr, bool is_const) -{ - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_hard_coded_addr(g, const_val, pointee_type, addr, is_const); - return const_val; -} - -ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count) { - return realloc_const_vals_ptrs(g, nullptr, 0, count); -} - -ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count) { - assert(new_count >= old_count); - - size_t new_item_count = new_count - old_count; - ZigValue **result = heap::c_allocator.reallocate(ptr, old_count, new_count); - ZigValue *vals = g->pass1_arena->allocate(new_item_count); - for (size_t i = old_count; i < new_count; i += 1) { - result[i] = &vals[i - old_count]; - } - return result; -} - -TypeStructField **alloc_type_struct_fields(size_t count) { - return realloc_type_struct_fields(nullptr, 0, count); -} - -TypeStructField **realloc_type_struct_fields(TypeStructField **ptr, size_t old_count, size_t new_count) { - assert(new_count >= old_count); - - size_t new_item_count = new_count - old_count; - TypeStructField **result = heap::c_allocator.reallocate(ptr, old_count, new_count); - TypeStructField *vals = heap::c_allocator.allocate(new_item_count); - for (size_t i = old_count; i < new_count; i += 1) { - result[i] = &vals[i - old_count]; - } - return result; -} - -static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { - if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) - return orig_fn_type; - - ZigType *fn_type = heap::c_allocator.allocate_nonzero(1); - *fn_type = *orig_fn_type; - fn_type->data.fn.fn_type_id.cc = CallingConventionAsync; - fn_type->llvm_type = nullptr; - fn_type->llvm_di_type = nullptr; - - return fn_type; -} - -// Traverse up to the very top ExprScope, which has children. -// We have just arrived at the top from a child. That child, -// and its next siblings, do not need to be marked. But the previous -// siblings do. -// x + (await y) -// vs -// (await y) + x -static void mark_suspension_point(Scope *scope) { - ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast(scope) : nullptr; - bool looking_for_exprs = true; - for (;;) { - scope = scope->parent; - switch (scope->id) { - case ScopeIdDeferExpr: - case ScopeIdDecls: - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdCImport: - case ScopeIdSuspend: - case ScopeIdTypeOf: - return; - case ScopeIdVarDecl: - case ScopeIdDefer: - case ScopeIdBlock: - looking_for_exprs = false; - continue; - case ScopeIdRuntime: - continue; - case ScopeIdLoop: { - ScopeLoop *loop_scope = reinterpret_cast(scope); - if (loop_scope->spill_scope != nullptr) { - loop_scope->spill_scope->need_spill = MemoizedBoolTrue; - } - looking_for_exprs = false; - continue; - } - case ScopeIdExpr: { - ScopeExpr *parent_expr_scope = reinterpret_cast(scope); - if (!looking_for_exprs) { - if (parent_expr_scope->spill_harder) { - parent_expr_scope->need_spill = MemoizedBoolTrue; - } - // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) - continue; - } - if (child_expr_scope != nullptr) { - for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { - assert(i < parent_expr_scope->children_len); - parent_expr_scope->children_ptr[i]->need_spill = MemoizedBoolTrue; - } - } - parent_expr_scope->need_spill = MemoizedBoolTrue; - child_expr_scope = parent_expr_scope; - continue; - } - } - } -} - -static bool scope_needs_spill(Scope *scope) { - ScopeExpr *scope_expr = find_expr_scope(scope); - if (scope_expr == nullptr) return false; - - switch (scope_expr->need_spill) { - case MemoizedBoolUnknown: - if (scope_needs_spill(scope_expr->base.parent)) { - scope_expr->need_spill = MemoizedBoolTrue; - return true; - } else { - scope_expr->need_spill = MemoizedBoolFalse; - return false; - } - case MemoizedBoolFalse: - return false; - case MemoizedBoolTrue: - return true; - } - zig_unreachable(); -} - -static ZigType *resolve_type_isf(ZigType *ty) { - if (ty->id != ZigTypeIdPointer) return ty; - InferredStructField *isf = ty->data.pointer.inferred_struct_field; - if (isf == nullptr) return ty; - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - return field->type_entry; -} - -static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { - Error err; - - if (frame_type->data.frame.locals_struct != nullptr) - return ErrorNone; - - ZigFn *fn = frame_type->data.frame.fn; - assert(!fn->type_entry->data.fn.is_generic); - - if (frame_type->data.frame.resolve_loop_type != nullptr) { - if (!frame_type->data.frame.reported_loop_err) { - add_node_error(g, fn->proto_node, - buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - switch (fn->anal_state) { - case FnAnalStateInvalid: - return ErrorSemanticAnalyzeFail; - case FnAnalStateComplete: - break; - case FnAnalStateReady: - analyze_fn_body(g, fn); - if (fn->anal_state == FnAnalStateInvalid) - return ErrorSemanticAnalyzeFail; - break; - case FnAnalStateProbing: { - add_node_error(g, fn->proto_node, - buf_sprintf("cannot resolve '%s': function not fully analyzed yet", - buf_ptr(&frame_type->name))); - return ErrorSemanticAnalyzeFail; - } - } - analyze_fn_async(g, fn, false); - if (fn->anal_state == FnAnalStateInvalid) - return ErrorSemanticAnalyzeFail; - - if (!fn_is_async(fn)) { - ZigType *fn_type = fn->type_entry; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false); - - // label (grep this): [fn_frame_struct_layout] - ZigList fields = {}; - - fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0}); - fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); - fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); - - fields.append({"@result_ptr_callee", ptr_return_type, 0}); - fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); - fields.append({"@result", fn_type_id->return_type, 0}); - - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - ZigType *ptr_to_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - fields.append({"@ptr_stack_trace_callee", ptr_to_stack_trace_type, 0}); - fields.append({"@ptr_stack_trace_awaiter", ptr_to_stack_trace_type, 0}); - - fields.append({"@stack_trace", get_stack_trace_type(g), 0}); - fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); - } - - frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), - fields.items, fields.length, target_fn_align(g->zig_target)); - frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size; - frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align; - frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits; - - return ErrorNone; - } - - ZigType *fn_type = get_async_fn_type(g, fn->type_entry); - - if (fn->analyzed_executable.need_err_code_spill) { - Stage1AirInstAlloca *alloca_gen = heap::c_allocator.create(); - alloca_gen->base.id = Stage1AirInstIdAlloca; - alloca_gen->base.source_node = fn->proto_node; - alloca_gen->base.scope = fn->child_scope; - alloca_gen->base.value = g->pass1_arena->create(); - alloca_gen->base.value->type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); - alloca_gen->base.ref_count = 1; - alloca_gen->name_hint = ""; - fn->alloca_gen_list.append(alloca_gen); - fn->err_code_spill = &alloca_gen->base; - } - - ZigType *largest_call_frame_type = nullptr; - // Later we'll change this to be largest_call_frame_type instead of void. - Stage1AirInst *all_calls_alloca = ir_create_alloca(g, &fn->fndef_scope->base, fn->body_node, - fn, g->builtin_types.entry_void, "@async_call_frame"); - - for (size_t i = 0; i < fn->call_list.length; i += 1) { - Stage1AirInstCall *call = fn->call_list.at(i); - if (call->new_stack != nullptr) { - // don't need to allocate a frame for this - continue; - } - ZigFn *callee = call->fn_entry; - if (callee == nullptr) { - if (call->fn_ref->value->type->data.fn.fn_type_id.cc != CallingConventionAsync) { - continue; - } - add_node_error(g, call->base.source_node, - buf_sprintf("function is not comptime-known; @asyncCall required")); - return ErrorSemanticAnalyzeFail; - } - if (callee->body_node == nullptr) { - continue; - } - if (callee->anal_state == FnAnalStateProbing) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name))); - g->trace_err = add_error_note(g, msg, call->base.source_node, - buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name))); - return ErrorSemanticAnalyzeFail; - } - - ZigType *callee_frame_type = get_fn_frame_type(g, callee); - frame_type->data.frame.resolve_loop_type = callee_frame_type; - frame_type->data.frame.resolve_loop_src_node = call->base.source_node; - - analyze_fn_body(g, callee); - if (callee->anal_state == FnAnalStateInvalid) { - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - analyze_fn_async(g, callee, true); - if (callee->inferred_async_node == inferred_async_checking) { - assert(g->errors.length != 0); - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - if (!fn_is_async(callee)) - continue; - - mark_suspension_point(call->base.scope); - - if ((err = type_resolve(g, callee_frame_type, ResolveStatusSizeKnown))) { - return err; - } - if (largest_call_frame_type == nullptr || - callee_frame_type->abi_size > largest_call_frame_type->abi_size) - { - largest_call_frame_type = callee_frame_type; - } - - call->frame_result_loc = all_calls_alloca; - } - if (largest_call_frame_type != nullptr) { - all_calls_alloca->value->type = get_pointer_to_type(g, largest_call_frame_type, false); - } - - // Since this frame is async, an await might represent a suspend point, and - // therefore need to spill. It also needs to mark expr scopes as having to spill. - // For example: foo() + await z - // The function call result of foo() must be spilled. - for (size_t i = 0; i < fn->await_list.length; i += 1) { - Stage1AirInstAwait *await = fn->await_list.at(i); - if (await->is_nosuspend) { - continue; - } - if (await->base.value->special != ConstValSpecialRuntime) { - // Known at comptime. No spill, no suspend. - continue; - } - if (await->target_fn != nullptr) { - // we might not need to suspend - analyze_fn_async(g, await->target_fn, false); - if (await->target_fn->anal_state == FnAnalStateInvalid) { - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - if (!fn_is_async(await->target_fn)) { - // This await does not represent a suspend point. No spill needed, - // and no need to mark ExprScope. - continue; - } - } - // This await is a suspend point, but it might not need a spill. - // We do need to mark the ExprScope as having a suspend point in it. - mark_suspension_point(await->base.scope); - - if (await->result_loc != nullptr) { - // If there's a result location, that is the spill - continue; - } - if (await->base.ref_count == 0) - continue; - if (!type_has_bits(g, await->base.value->type)) - continue; - await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn, - await->base.value->type, ""); - } - for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i); - for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = block->instruction_list.at(instr_i); - if (instruction->id == Stage1AirInstIdSuspendFinish) { - mark_suspension_point(instruction->scope); - } - } - } - // Now that we've marked all the expr scopes that have to spill, we go over the instructions - // and spill the relevant ones. - for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i); - for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = block->instruction_list.at(instr_i); - if (instruction->id == Stage1AirInstIdAwait || - instruction->id == Stage1AirInstIdVarPtr || - instruction->id == Stage1AirInstIdAlloca || - instruction->id == Stage1AirInstIdSpillBegin || - instruction->id == Stage1AirInstIdSpillEnd) - { - // This instruction does its own spilling specially, or otherwise doesn't need it. - continue; - } - if (instruction->id == Stage1AirInstIdCast && - reinterpret_cast(instruction)->cast_op == CastOpNoop) - { - // The IR instruction exists only to change the type according to Zig. No spill needed. - continue; - } - if (instruction->value->special != ConstValSpecialRuntime) - continue; - if (instruction->ref_count == 0) - continue; - if ((err = type_resolve(g, instruction->value->type, ResolveStatusZeroBitsKnown))) - return ErrorSemanticAnalyzeFail; - if (!type_has_bits(g, instruction->value->type)) - continue; - if (scope_needs_spill(instruction->scope)) { - instruction->spill = ir_create_alloca(g, instruction->scope, instruction->source_node, - fn, instruction->value->type, ""); - } - } - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false); - - // label (grep this): [fn_frame_struct_layout] - ZigList fields = {}; - - fields.append({"@fn_ptr", fn_type, 0}); - fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); - fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); - - fields.append({"@result_ptr_callee", ptr_return_type, 0}); - fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); - fields.append({"@result", fn_type_id->return_type, 0}); - - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - ZigType *ptr_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - fields.append({"@ptr_stack_trace_callee", ptr_stack_trace_type, 0}); - fields.append({"@ptr_stack_trace_awaiter", ptr_stack_trace_type, 0}); - } - - for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i]; - AstNode *param_decl_node = get_param_decl_node(fn, arg_i); - Buf *param_name; - bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; - if (param_decl_node && !is_var_args) { - param_name = param_decl_node->data.param_decl.name; - } else { - param_name = buf_sprintf("@arg%" ZIG_PRI_usize, arg_i); - } - ZigType *param_type = resolve_type_isf(param_info->type); - if ((err = type_resolve(g, param_type, ResolveStatusSizeKnown))) { - return err; - } - - fields.append({buf_ptr(param_name), param_type, 0}); - } - - if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) { - fields.append({"@stack_trace", get_stack_trace_type(g), 0}); - fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); - } - - for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = fn->alloca_gen_list.at(alloca_i); - instruction->field_index = SIZE_MAX; - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = resolve_type_isf(ptr_type->data.pointer.child_type); - if (!type_has_bits(g, child_type)) - continue; - if (instruction->base.ref_count == 0) - continue; - if (instruction->base.value->special != ConstValSpecialRuntime) { - if (const_ptr_pointee(nullptr, g, instruction->base.value, nullptr)->special != - ConstValSpecialRuntime) - { - continue; - } - } - - frame_type->data.frame.resolve_loop_type = child_type; - frame_type->data.frame.resolve_loop_src_node = instruction->base.source_node; - if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - return err; - } - - const char *name; - if (*instruction->name_hint == 0) { - name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i)); - } else { - name = buf_ptr(buf_sprintf("%s.%" ZIG_PRI_usize, instruction->name_hint, alloca_i)); - } - instruction->field_index = fields.length; - - fields.append({name, child_type, instruction->align}); - } - - - frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), - fields.items, fields.length, target_fn_align(g->zig_target)); - frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size; - frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align; - frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits; - - if (g->largest_frame_fn == nullptr || frame_type->abi_size > g->largest_frame_fn->frame_type->abi_size) { - g->largest_frame_fn = fn; - } - - return ErrorNone; -} - -static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { - Error err; - - if (ty->abi_size != SIZE_MAX) - return ErrorNone; - - if (ty->data.pointer.resolve_loop_flag_zero_bits) { - ty->abi_size = g->builtin_types.entry_usize->abi_size; - ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - ty->abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - } - ty->data.pointer.resolve_loop_flag_zero_bits = true; - - ZigType *elem_type; - InferredStructField *isf = ty->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - ty->data.pointer.resolve_loop_flag_zero_bits = false; - - ty->abi_size = 0; - ty->size_in_bits = 0; - ty->abi_align = 0; - - return ErrorNone; - } - elem_type = field->type_entry; - } else { - elem_type = ty->data.pointer.child_type; - } - - bool has_bits; - if ((err = type_has_bits2(g, elem_type, &has_bits))) - return err; - - ty->data.pointer.resolve_loop_flag_zero_bits = false; - - if (has_bits) { - ty->abi_size = g->builtin_types.entry_usize->abi_size; - ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - ty->abi_align = g->builtin_types.entry_usize->abi_align; - } else { - ty->abi_size = 0; - ty->size_in_bits = 0; - ty->abi_align = 0; - } - return ErrorNone; -} - -Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { - if (type_is_invalid(ty)) - return ErrorSemanticAnalyzeFail; - switch (status) { - case ResolveStatusUnstarted: - return ErrorNone; - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusZeroBitsKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_zero_bits(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_zero_bits(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusAlignmentKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_alignment(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_alignment(g, ty); - case ZigTypeIdFnFrame: - return resolve_async_frame(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusSizeKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_type(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_type(g, ty); - case ZigTypeIdFnFrame: - return resolve_async_frame(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - resolve_llvm_types(g, ty, status); - return ErrorNone; - } - zig_unreachable(); -} - -bool ir_get_var_is_comptime(ZigVar *var) { - if (var->is_comptime_memoized) - return var->is_comptime_memoized_value; - - var->is_comptime_memoized = true; - - // The is_comptime field can be left null, which means not comptime. - if (var->is_comptime == nullptr) { - var->is_comptime_memoized_value = false; - return var->is_comptime_memoized_value; - } - // When the is_comptime field references an instruction that has to get analyzed, this - // is the value. - if (var->is_comptime->child != nullptr) { - assert(var->is_comptime->child->value->type->id == ZigTypeIdBool); - var->is_comptime_memoized_value = var->is_comptime->child->value->data.x_bool; - var->is_comptime = nullptr; - return var->is_comptime_memoized_value; - } - // As an optimization, is_comptime values which are constant are allowed - // to be omitted from analysis. In this case, there is no child instruction - // and we simply look at the unanalyzed const parent instruction. - assert(var->is_comptime->id == Stage1ZirInstIdConst); - Stage1ZirInstConst *const_inst = reinterpret_cast(var->is_comptime); - assert(const_inst->value->type->id == ZigTypeIdBool); - var->is_comptime_memoized_value = const_inst->value->data.x_bool; - var->is_comptime = nullptr; - return var->is_comptime_memoized_value; -} - -bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { - if (a->data.x_ptr.special != b->data.x_ptr.special) - return false; - switch (a->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) - return false; - return true; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { - return false; - } - if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) - return false; - return true; - case ConstPtrSpecialBaseStruct: - if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val) { - return false; - } - if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) - return false; - return true; - case ConstPtrSpecialBaseErrorUnionCode: - if (a->data.x_ptr.data.base_err_union_code.err_union_val != - b->data.x_ptr.data.base_err_union_code.err_union_val) - { - return false; - } - return true; - case ConstPtrSpecialBaseErrorUnionPayload: - if (a->data.x_ptr.data.base_err_union_payload.err_union_val != - b->data.x_ptr.data.base_err_union_payload.err_union_val) - { - return false; - } - return true; - case ConstPtrSpecialBaseOptionalPayload: - if (a->data.x_ptr.data.base_optional_payload.optional_val != - b->data.x_ptr.data.base_optional_payload.optional_val) - { - return false; - } - return true; - case ConstPtrSpecialHardCodedAddr: - if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) - return false; - return true; - case ConstPtrSpecialDiscard: - return true; - case ConstPtrSpecialFunction: - return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; - case ConstPtrSpecialNull: - return true; - } - zig_unreachable(); -} - -static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) { - if (a->data.x_array.special == ConstArraySpecialUndef && - b->data.x_array.special == ConstArraySpecialUndef) - { - return true; - } - if (a->data.x_array.special == ConstArraySpecialUndef || - b->data.x_array.special == ConstArraySpecialUndef) - { - return false; - } - if (a->data.x_array.special == ConstArraySpecialBuf && - b->data.x_array.special == ConstArraySpecialBuf) - { - return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); - } - expand_undef_array(g, a); - expand_undef_array(g, b); - - ZigValue *a_elems = a->data.x_array.data.s_none.elements; - ZigValue *b_elems = b->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; -} - -bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { - if (a->type->id != b->type->id) return false; - if (a->type == b->type) { - switch (type_has_one_possible_value(g, a->type)) { - case OnePossibleValueInvalid: - zig_unreachable(); - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - return true; - } - } - if (a->special == ConstValSpecialUndef || b->special == ConstValSpecialUndef) { - return a->special == b->special; - } - assert(a->special == ConstValSpecialStatic); - assert(b->special == ConstValSpecialStatic); - switch (a->type->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdEnum: - return bigint_cmp(&a->data.x_enum_tag, &b->data.x_enum_tag) == CmpEQ; - case ZigTypeIdUnion: { - ConstUnionValue *union1 = &a->data.x_union; - ConstUnionValue *union2 = &b->data.x_union; - - if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) { - TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag); - assert(field != nullptr); - assert(find_union_field_by_tag(a->type, &union2->tag) != nullptr); - return const_values_equal(g, union1->payload, union2->payload); - } - return false; - } - case ZigTypeIdMetaType: - return a->data.x_type == b->data.x_type; - case ZigTypeIdVoid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - return true; - case ZigTypeIdErrorSet: - return a->data.x_err_set->value == b->data.x_err_set->value; - case ZigTypeIdBool: - return a->data.x_bool == b->data.x_bool; - case ZigTypeIdFloat: - assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count); - switch (a->type->data.floating.bit_count) { - case 16: - return f16_eq(a->data.x_f16, b->data.x_f16); - case 32: - return a->data.x_f32 == b->data.x_f32; - case 64: - return a->data.x_f64 == b->data.x_f64; - case 80: - return extF80M_eq(&a->data.x_f80, &b->data.x_f80); - case 128: - return f128M_eq(&a->data.x_f128, &b->data.x_f128); - default: - zig_unreachable(); - } - case ZigTypeIdComptimeFloat: - return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ; - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; - case ZigTypeIdEnumLiteral: - return buf_eql_buf(a->data.x_enum_literal, b->data.x_enum_literal); - case ZigTypeIdPointer: - case ZigTypeIdFn: - return const_values_equal_ptr(a, b); - case ZigTypeIdVector: - assert(a->type->data.vector.len == b->type->data.vector.len); - return const_values_equal_array(g, a, b, a->type->data.vector.len); - case ZigTypeIdArray: - assert(a->type->data.array.len == b->type->data.array.len); - return const_values_equal_array(g, a, b, a->type->data.array.len); - case ZigTypeIdStruct: - for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { - if (a->type->data.structure.fields[i]->is_comptime) { - // The values of comptime struct fields are part of the - // type, not the value, so they do not participate in equality - // or hash of comptime values. - continue; - } - ZigValue *field_a = a->data.x_struct.fields[i]; - ZigValue *field_b = b->data.x_struct.fields[i]; - if (!const_values_equal(g, field_a, field_b)) - return false; - } - return true; - case ZigTypeIdFnFrame: - zig_panic("TODO: const_values_equal ZigTypeIdFnFrame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO: const_values_equal ZigTypeIdAnyFrame"); - case ZigTypeIdOptional: - if (get_src_ptr_type(a->type) != nullptr) - return const_values_equal_ptr(a, b); - if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) { - return (a->data.x_optional == nullptr && b->data.x_optional == nullptr); - } else { - return const_values_equal(g, a->data.x_optional, b->data.x_optional); - } - case ZigTypeIdErrorUnion: { - bool a_is_err = a->data.x_err_union.error_set->data.x_err_set != nullptr; - bool b_is_err = b->data.x_err_union.error_set->data.x_err_set != nullptr; - if (a_is_err != b_is_err) return false; - if (a_is_err) { - return const_values_equal(g, a->data.x_err_union.error_set, b->data.x_err_union.error_set); - } else { - return const_values_equal(g, a->data.x_err_union.payload, b->data.x_err_union.payload); - } - } - case ZigTypeIdBoundFn: - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - } - zig_unreachable(); -} - -void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max) { - assert(int_type->id == ZigTypeIdInt); - if (int_type->data.integral.bit_count == 0) { - bigint_init_unsigned(bigint, 0); - return; - } - if (is_max) { - // is_signed=true (1 << (bit_count - 1)) - 1 - // is_signed=false (1 << (bit_count - 0)) - 1 - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - size_t shift_amt = int_type->data.integral.bit_count - (int_type->data.integral.is_signed ? 1 : 0); - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, shift_amt); - - BigInt shifted_bi = {0}; - bigint_shl(&shifted_bi, &one, &bit_count_bi); - - bigint_sub(bigint, &shifted_bi, &one); - } else if (int_type->data.integral.is_signed) { - // - (1 << (bit_count - 1)) - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, int_type->data.integral.bit_count - 1); - - BigInt shifted_bi = {0}; - bigint_shl(&shifted_bi, &one, &bit_count_bi); - - bigint_negate(bigint, &shifted_bi); - } else { - bigint_init_unsigned(bigint, 0); - } -} - -void eval_min_max_value(CodeGen *g, ZigType *type_entry, ZigValue *const_val, bool is_max) { - if (type_entry->id == ZigTypeIdInt) { - const_val->special = ConstValSpecialStatic; - eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max); - } else if (type_entry->id == ZigTypeIdBool) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_bool = is_max; - } else if (type_entry->id == ZigTypeIdVoid) { - // nothing to do - } else { - zig_unreachable(); - } -} - -static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigType *type_entry) { - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { - buf_append_buf(buf, &type_entry->name); - return; - } - - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - case ConstPtrSpecialBaseStruct: - case ConstPtrSpecialBaseErrorUnionCode: - case ConstPtrSpecialBaseErrorUnionPayload: - case ConstPtrSpecialBaseOptionalPayload: - buf_appendf(buf, "*"); - // TODO we need a source node for const_ptr_pointee because it can generate compile errors - render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); - return; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - buf_appendf(buf, "*"); - // TODO we need a source node for const_ptr_pointee because it can generate compile errors - render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); - return; - case ConstPtrSpecialHardCodedAddr: - buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name), - const_val->data.x_ptr.data.hard_coded_addr.addr); - return; - case ConstPtrSpecialDiscard: - buf_append_str(buf, "*_"); - return; - case ConstPtrSpecialFunction: - { - ZigFn *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; - buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); - return; - } - case ConstPtrSpecialNull: - buf_append_str(buf, "null"); - return; - } - zig_unreachable(); -} - -static void render_const_val_err_set(CodeGen *g, Buf *buf, ZigValue *const_val, ZigType *type_entry) { - if (const_val->data.x_err_set == nullptr) { - buf_append_str(buf, "null"); - } else { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); - } -} - -static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ZigValue *const_val, uint64_t start, uint64_t len) { - ConstArrayValue *array = &const_val->data.x_array; - switch (array->special) { - case ConstArraySpecialUndef: - buf_append_str(buf, "undefined"); - return; - case ConstArraySpecialBuf: { - Buf *array_buf = array->data.s_buf; - const char *base = &buf_ptr(array_buf)[start]; - assert(start + len <= buf_len(array_buf)); - - buf_append_char(buf, '"'); - for (size_t i = 0; i < len; i += 1) { - uint8_t c = base[i]; - if (c == '"') { - buf_append_str(buf, "\\\""); - } else { - buf_append_char(buf, c); - } - } - buf_append_char(buf, '"'); - return; - } - case ConstArraySpecialNone: { - assert(start + len <= const_val->type->data.array.len); - ZigValue *base = &array->data.s_none.elements[start]; - assert(len == 0 || base != nullptr); - - buf_appendf(buf, "%s{", buf_ptr(type_name)); - for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) buf_appendf(buf, ","); - render_const_value(g, buf, &base[i]); - } - buf_appendf(buf, "}"); - return; - } - } - zig_unreachable(); -} - -void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) { - if (const_val == nullptr) { - buf_appendf(buf, "(invalid nullptr value)"); - return; - } - switch (const_val->special) { - case ConstValSpecialRuntime: - buf_appendf(buf, "(runtime value)"); - return; - case ConstValSpecialLazy: - buf_appendf(buf, "(lazy value)"); - return; - case ConstValSpecialUndef: - buf_appendf(buf, "undefined"); - return; - case ConstValSpecialStatic: - break; - } - assert(const_val->type); - - ZigType *type_entry = const_val->type; - switch (type_entry->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdInvalid: - buf_appendf(buf, "(invalid)"); - return; - case ZigTypeIdVoid: - buf_appendf(buf, "{}"); - return; - case ZigTypeIdComptimeFloat: - bigfloat_append_buf(buf, &const_val->data.x_bigfloat); - return; - case ZigTypeIdFloat: - switch (type_entry->data.floating.bit_count) { - case 16: - buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16)); - return; - case 32: - buf_appendf(buf, "%f", const_val->data.x_f32); - return; - case 64: - buf_appendf(buf, "%f", const_val->data.x_f64); - return; - case 80: { - float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - buf_appendf(buf, "%f", double_value); - return; - } - case 128: - { - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - float64_t f64_value = f128M_to_f64(&const_val->data.x_f128); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - // TODO actual f128 printing to decimal - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); - return; - } - default: - zig_unreachable(); - } - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - bigint_append_buf(buf, &const_val->data.x_bigint, 10); - return; - case ZigTypeIdEnumLiteral: - buf_append_buf(buf, const_val->data.x_enum_literal); - return; - case ZigTypeIdMetaType: - buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); - return; - case ZigTypeIdUnreachable: - buf_appendf(buf, "unreachable"); - return; - case ZigTypeIdBool: - { - const char *value = const_val->data.x_bool ? "true" : "false"; - buf_appendf(buf, "%s", value); - return; - } - case ZigTypeIdFn: - { - assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); - ZigFn *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; - buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name)); - return; - } - case ZigTypeIdPointer: - return render_const_val_ptr(g, buf, const_val, type_entry); - case ZigTypeIdArray: { - uint64_t len = type_entry->data.array.len; - render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); - return; - } - case ZigTypeIdVector: { - uint32_t len = type_entry->data.vector.len; - render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); - return; - } - case ZigTypeIdNull: - { - buf_appendf(buf, "null"); - return; - } - case ZigTypeIdUndefined: - { - buf_appendf(buf, "undefined"); - return; - } - case ZigTypeIdOptional: - { - ZigType *src_ptr_type = get_src_ptr_type(const_val->type); - if (src_ptr_type != nullptr) { - if (src_ptr_type->id == ZigTypeIdPointer && !optional_value_is_null(const_val)) { - ZigValue tmp = {}; - copy_const_val(g, &tmp, const_val); - tmp.type = type_entry->data.maybe.child_type; - return render_const_val_ptr(g, buf, &tmp, tmp.type); - } - return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); - } - if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) - return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); - if (const_val->data.x_optional) { - render_const_value(g, buf, const_val->data.x_optional); - } else { - buf_appendf(buf, "null"); - } - return; - } - case ZigTypeIdBoundFn: - { - ZigFn *fn_entry = const_val->data.x_bound_fn.fn; - buf_appendf(buf, "(bound fn %s)", buf_ptr(&fn_entry->symbol_name)); - return; - } - case ZigTypeIdStruct: - { - if (is_slice(type_entry)) { - ZigValue *len_val = const_val->data.x_struct.fields[slice_len_index]; - size_t len = bigint_as_usize(&len_val->data.x_bigint); - - ZigValue *ptr_val = const_val->data.x_struct.fields[slice_ptr_index]; - if (ptr_val->special == ConstValSpecialUndef) { - assert(len == 0); - buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name)); - return; - } - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array = ptr_val->data.x_ptr.data.base_array.array_val; - size_t start = ptr_val->data.x_ptr.data.base_array.elem_index; - - if (array->special == ConstValSpecialUndef) - buf_append_str(buf, "undefined"); - else - render_const_val_array(g, buf, &type_entry->name, array, start, len); - } else { - buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); - } - return; - } - case ZigTypeIdEnum: - { - TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag); - if(field != nullptr){ - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name)); - } else { - // untagged value in a non-exhaustive enum - buf_appendf(buf, "%s.(", buf_ptr(&type_entry->name)); - bigint_append_buf(buf, &const_val->data.x_enum_tag, 10); - buf_appendf(buf, ")"); - } - return; - } - case ZigTypeIdErrorUnion: - { - buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - if (err_set == nullptr) { - render_const_value(g, buf, const_val->data.x_err_union.payload); - } else { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), - buf_ptr(&err_set->name)); - } - buf_appendf(buf, ")"); - return; - } - case ZigTypeIdUnion: - { - const BigInt *tag = &const_val->data.x_union.tag; - TypeUnionField *field = find_union_field_by_tag(type_entry, tag); - buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name)); - render_const_value(g, buf, const_val->data.x_union.payload); - buf_append_str(buf, "}"); - return; - } - case ZigTypeIdErrorSet: - return render_const_val_err_set(g, buf, const_val, type_entry); - case ZigTypeIdFnFrame: - buf_appendf(buf, "(TODO: async function frame value)"); - return; - - case ZigTypeIdAnyFrame: - buf_appendf(buf, "(TODO: anyframe value)"); - return; - - } - zig_unreachable(); -} - -ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { - assert(size_in_bits <= 65535); - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - - entry->size_in_bits = size_in_bits; - if (size_in_bits != 0) { - entry->llvm_type = LLVMIntType(size_in_bits); - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - if (size_in_bits >= 128 && entry->abi_align < 16) { - // Override the incorrect alignment reported by LLVM. Clang does this as well. - // On x86_64 there are some instructions like CMPXCHG16B which require this. - // On all targets, integers 128 bits and above have ABI alignment of 16. - // However for some targets, LLVM incorrectly reports this as 8. - // See: https://github.com/ziglang/zig/issues/2987 - entry->abi_align = 16; - entry->abi_size = align_forward(entry->abi_size, entry->abi_align); - } - } - - const char u_or_i = is_signed ? 'i' : 'u'; - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%c%" PRIu32, u_or_i, size_in_bits); - - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = size_in_bits; - return entry; -} - -uint32_t type_id_hash(TypeId const *x) { - uint32_t hash = hash_combine(HASH_INIT, &x->id); - switch (x->id) { - case ZigTypeIdInvalid: - case ZigTypeIdOpaque: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - zig_unreachable(); - case ZigTypeIdErrorUnion: - hash = hash_combine(hash, &x->data.error_union.err_set_type); - hash = hash_combine(hash, &x->data.error_union.payload_type); - return hash; - case ZigTypeIdPointer: - hash = hash_combine(hash, &x->data.pointer.child_type); - hash = hash_combine(hash, &x->data.pointer.ptr_len); - hash = hash_combine(hash, &x->data.pointer.is_const); - hash = hash_combine(hash, &x->data.pointer.is_volatile); - hash = hash_combine(hash, &x->data.pointer.allow_zero); - hash = hash_combine(hash, &x->data.pointer.alignment); - hash = hash_combine(hash, &x->data.pointer.bit_offset_in_host); - hash = hash_combine(hash, &x->data.pointer.vector_index); - hash = hash_combine(hash, &x->data.pointer.host_int_bytes); - if (x->data.pointer.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x->data.pointer.sentinel); - } - if (x->data.pointer.inferred_struct_field) { - hash = hash_combine(hash, &x->data.pointer.inferred_struct_field->inferred_struct_type); - hash = hash_combine_buf(hash, x->data.pointer.inferred_struct_field->field_name); - } - return hash; - case ZigTypeIdArray: - hash = hash_combine(hash, &x->data.array.child_type); - hash = hash_combine(hash, &x->data.array.size); - if (x->data.array.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x->data.array.sentinel); - } - return hash; - case ZigTypeIdInt: - hash = hash_combine(hash, &x->data.integer.is_signed); - hash = hash_combine(hash, &x->data.integer.bit_count); - return hash; - case ZigTypeIdVector: - hash = hash_combine(hash, &x->data.vector.elem_type); - hash = hash_combine(hash, &x->data.vector.len); - return hash; - } - zig_unreachable(); -} - -bool type_id_eql(TypeId const *a, TypeId const *b) { - if (a->id != b->id) - return false; - switch (a->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - zig_unreachable(); - case ZigTypeIdErrorUnion: - return a->data.error_union.err_set_type == b->data.error_union.err_set_type && - a->data.error_union.payload_type == b->data.error_union.payload_type; - - case ZigTypeIdPointer: - return a->data.pointer.child_type == b->data.pointer.child_type && - a->data.pointer.ptr_len == b->data.pointer.ptr_len && - a->data.pointer.is_const == b->data.pointer.is_const && - a->data.pointer.is_volatile == b->data.pointer.is_volatile && - a->data.pointer.allow_zero == b->data.pointer.allow_zero && - a->data.pointer.alignment == b->data.pointer.alignment && - a->data.pointer.bit_offset_in_host == b->data.pointer.bit_offset_in_host && - a->data.pointer.vector_index == b->data.pointer.vector_index && - a->data.pointer.host_int_bytes == b->data.pointer.host_int_bytes && - ( - a->data.pointer.sentinel == b->data.pointer.sentinel || - (a->data.pointer.sentinel != nullptr && b->data.pointer.sentinel != nullptr && - const_values_equal(a->data.pointer.codegen, a->data.pointer.sentinel, b->data.pointer.sentinel)) - ) && - ( - a->data.pointer.inferred_struct_field == b->data.pointer.inferred_struct_field || - (a->data.pointer.inferred_struct_field != nullptr && - b->data.pointer.inferred_struct_field != nullptr && - a->data.pointer.inferred_struct_field->inferred_struct_type == - b->data.pointer.inferred_struct_field->inferred_struct_type && - buf_eql_buf(a->data.pointer.inferred_struct_field->field_name, - b->data.pointer.inferred_struct_field->field_name)) - ); - case ZigTypeIdArray: - return a->data.array.child_type == b->data.array.child_type && - a->data.array.size == b->data.array.size && - ( - a->data.array.sentinel == b->data.array.sentinel || - (a->data.array.sentinel != nullptr && b->data.array.sentinel != nullptr && - const_values_equal(a->data.array.codegen, a->data.array.sentinel, b->data.array.sentinel)) - ); - case ZigTypeIdInt: - return a->data.integer.is_signed == b->data.integer.is_signed && - a->data.integer.bit_count == b->data.integer.bit_count; - case ZigTypeIdVector: - return a->data.vector.elem_type == b->data.vector.elem_type && - a->data.vector.len == b->data.vector.len; - } - zig_unreachable(); -} - -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) { - switch (x->id) { - case ZigLLVMFnIdCtz: - return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934 + - (uint32_t)(x->data.ctz.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdClz: - return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817 + - (uint32_t)(x->data.clz.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdPopCount: - return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 + - (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdFloatOp: - return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + - (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025) + - (uint32_t)(x->data.floating.op) * (uint32_t)43789879; - case ZigLLVMFnIdFMA: - return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + - (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdBswap: - return (uint32_t)(x->data.bswap.bit_count) * ((uint32_t)3661994335) + - (uint32_t)(x->data.bswap.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdBitReverse: - return (uint32_t)(x->data.bit_reverse.bit_count) * (uint32_t)2621398431; - case ZigLLVMFnIdOverflowArithmetic: - return ((uint32_t)(x->data.overflow_arithmetic.bit_count) * 87135777) + - ((uint32_t)(x->data.overflow_arithmetic.add_sub_mul) * 31640542) + - ((uint32_t)(x->data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820) + - x->data.overflow_arithmetic.vector_len * 1435156945; - } - zig_unreachable(); -} - -bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b) { - if (a->id != b->id) - return false; - switch (a->id) { - case ZigLLVMFnIdCtz: - return a->data.ctz.bit_count == b->data.ctz.bit_count; - case ZigLLVMFnIdClz: - return a->data.clz.bit_count == b->data.clz.bit_count; - case ZigLLVMFnIdPopCount: - return a->data.pop_count.bit_count == b->data.pop_count.bit_count; - case ZigLLVMFnIdBswap: - return a->data.bswap.bit_count == b->data.bswap.bit_count && - a->data.bswap.vector_len == b->data.bswap.vector_len; - case ZigLLVMFnIdBitReverse: - return a->data.bit_reverse.bit_count == b->data.bit_reverse.bit_count; - case ZigLLVMFnIdFloatOp: - return a->data.floating.bit_count == b->data.floating.bit_count && - a->data.floating.vector_len == b->data.floating.vector_len && - a->data.floating.op == b->data.floating.op; - case ZigLLVMFnIdFMA: - return a->data.floating.bit_count == b->data.floating.bit_count && - a->data.floating.vector_len == b->data.floating.vector_len; - case ZigLLVMFnIdOverflowArithmetic: - return (a->data.overflow_arithmetic.bit_count == b->data.overflow_arithmetic.bit_count) && - (a->data.overflow_arithmetic.add_sub_mul == b->data.overflow_arithmetic.add_sub_mul) && - (a->data.overflow_arithmetic.is_signed == b->data.overflow_arithmetic.is_signed) && - (a->data.overflow_arithmetic.vector_len == b->data.overflow_arithmetic.vector_len); - } - zig_unreachable(); -} - -static void init_const_undefined(CodeGen *g, ZigValue *const_val) { - Error err; - ZigType *wanted_type = const_val->type; - if (wanted_type->id == ZigTypeIdArray) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.special = ConstArraySpecialUndef; - } else if (wanted_type->id == ZigTypeIdStruct) { - if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { - return; - } - - const_val->special = ConstValSpecialStatic; - size_t field_count = wanted_type->data.structure.src_field_count; - const_val->data.x_struct.fields = alloc_const_vals_ptrs(g, field_count); - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = wanted_type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, and do not need to - // be initialized. - continue; - } - - ZigValue *field_val = const_val->data.x_struct.fields[i]; - field_val->type = resolve_struct_field_type(g, wanted_type->data.structure.fields[i]); - assert(field_val->type); - init_const_undefined(g, field_val); - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = const_val; - field_val->parent.data.p_struct.field_index = i; - } - } else { - const_val->special = ConstValSpecialUndef; - } -} - -void expand_undef_struct(CodeGen *g, ZigValue *const_val) { - if (const_val->special == ConstValSpecialUndef) { - init_const_undefined(g, const_val); - } -} - -// Canonicalize the array value as ConstArraySpecialNone -void expand_undef_array(CodeGen *g, ZigValue *const_val) { - size_t elem_count; - ZigType *elem_type; - if (const_val->type->id == ZigTypeIdArray) { - elem_count = const_val->type->data.array.len; - elem_type = const_val->type->data.array.child_type; - } else if (const_val->type->id == ZigTypeIdVector) { - elem_count = const_val->type->data.vector.len; - elem_type = const_val->type->data.vector.elem_type; - } else { - zig_unreachable(); - } - if (const_val->special == ConstValSpecialUndef) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.special = ConstArraySpecialUndef; - } - switch (const_val->data.x_array.special) { - case ConstArraySpecialNone: - return; - case ConstArraySpecialUndef: { - const_val->data.x_array.special = ConstArraySpecialNone; - const_val->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; - element_val->type = elem_type; - init_const_undefined(g, element_val); - element_val->parent.id = ConstParentIdArray; - element_val->parent.data.p_array.array_val = const_val; - element_val->parent.data.p_array.elem_index = i; - } - return; - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - // If we're doing this it means that we are potentially modifying the data, - // so we can't have it be in the string literals table - g->string_literals_table.maybe_remove(buf); - - const_val->data.x_array.special = ConstArraySpecialNone; - assert(elem_count == buf_len(buf)); - const_val->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *this_char = &const_val->data.x_array.data.s_none.elements[i]; - this_char->special = ConstValSpecialStatic; - this_char->type = g->builtin_types.entry_u8; - bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); - this_char->parent.id = ConstParentIdArray; - this_char->parent.data.p_array.array_val = const_val; - this_char->parent.data.p_array.elem_index = i; - } - return; - } - } - zig_unreachable(); -} - -static const ZigTypeId all_type_ids[] = { - ZigTypeIdMetaType, - ZigTypeIdVoid, - ZigTypeIdBool, - ZigTypeIdUnreachable, - ZigTypeIdInt, - ZigTypeIdFloat, - ZigTypeIdPointer, - ZigTypeIdArray, - ZigTypeIdStruct, - ZigTypeIdComptimeFloat, - ZigTypeIdComptimeInt, - ZigTypeIdUndefined, - ZigTypeIdNull, - ZigTypeIdOptional, - ZigTypeIdErrorUnion, - ZigTypeIdErrorSet, - ZigTypeIdEnum, - ZigTypeIdUnion, - ZigTypeIdFn, - ZigTypeIdBoundFn, - ZigTypeIdOpaque, - ZigTypeIdFnFrame, - ZigTypeIdAnyFrame, - ZigTypeIdVector, - ZigTypeIdEnumLiteral, -}; - -ZigTypeId type_id_at_index(size_t index) { - assert(index < array_length(all_type_ids)); - return all_type_ids[index]; -} - -size_t type_id_len() { - return array_length(all_type_ids); -} - -size_t type_id_index(ZigType *entry) { - switch (entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return 0; - case ZigTypeIdVoid: - return 1; - case ZigTypeIdBool: - return 2; - case ZigTypeIdUnreachable: - return 3; - case ZigTypeIdInt: - return 4; - case ZigTypeIdFloat: - return 5; - case ZigTypeIdPointer: - return 6; - case ZigTypeIdArray: - return 7; - case ZigTypeIdStruct: - if (entry->data.structure.special == StructSpecialSlice) - return 6; - return 8; - case ZigTypeIdComptimeFloat: - return 9; - case ZigTypeIdComptimeInt: - return 10; - case ZigTypeIdUndefined: - return 11; - case ZigTypeIdNull: - return 12; - case ZigTypeIdOptional: - return 13; - case ZigTypeIdErrorUnion: - return 14; - case ZigTypeIdErrorSet: - return 15; - case ZigTypeIdEnum: - return 16; - case ZigTypeIdUnion: - return 17; - case ZigTypeIdFn: - return 18; - case ZigTypeIdBoundFn: - return 19; - case ZigTypeIdOpaque: - return 20; - case ZigTypeIdFnFrame: - return 21; - case ZigTypeIdAnyFrame: - return 22; - case ZigTypeIdVector: - return 23; - case ZigTypeIdEnumLiteral: - return 24; - } - zig_unreachable(); -} - -const char *type_id_name(ZigTypeId id) { - switch (id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return "Type"; - case ZigTypeIdVoid: - return "Void"; - case ZigTypeIdBool: - return "Bool"; - case ZigTypeIdUnreachable: - return "NoReturn"; - case ZigTypeIdInt: - return "Int"; - case ZigTypeIdFloat: - return "Float"; - case ZigTypeIdPointer: - return "Pointer"; - case ZigTypeIdArray: - return "Array"; - case ZigTypeIdStruct: - return "Struct"; - case ZigTypeIdComptimeFloat: - return "ComptimeFloat"; - case ZigTypeIdComptimeInt: - return "ComptimeInt"; - case ZigTypeIdEnumLiteral: - return "EnumLiteral"; - case ZigTypeIdUndefined: - return "Undefined"; - case ZigTypeIdNull: - return "Null"; - case ZigTypeIdOptional: - return "Optional"; - case ZigTypeIdErrorUnion: - return "ErrorUnion"; - case ZigTypeIdErrorSet: - return "ErrorSet"; - case ZigTypeIdEnum: - return "Enum"; - case ZigTypeIdUnion: - return "Union"; - case ZigTypeIdFn: - return "Fn"; - case ZigTypeIdBoundFn: - return "BoundFn"; - case ZigTypeIdOpaque: - return "Opaque"; - case ZigTypeIdVector: - return "Vector"; - case ZigTypeIdFnFrame: - return "Frame"; - case ZigTypeIdAnyFrame: - return "AnyFrame"; - } - zig_unreachable(); -} - -ZigType *get_align_amt_type(CodeGen *g) { - if (g->align_amt_type == nullptr) { - // according to LLVM the maximum alignment is 1 << 29. - g->align_amt_type = get_int_type(g, false, 29); - } - return g->align_amt_type; -} - -uint32_t type_ptr_hash(const ZigType *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool type_ptr_eql(const ZigType *a, const ZigType *b) { - return a == b; -} - -uint32_t pkg_ptr_hash(const ZigPackage *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b) { - return a == b; -} - -uint32_t tld_ptr_hash(const Tld *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool tld_ptr_eql(const Tld *a, const Tld *b) { - return a == b; -} - -uint32_t node_ptr_hash(const AstNode *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool node_ptr_eql(const AstNode *a, const AstNode *b) { - return a == b; -} - -uint32_t fn_ptr_hash(const ZigFn *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) { - return a == b; -} - -uint32_t err_ptr_hash(const ErrorTableEntry *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b) { - return a == b; -} - -ZigValue *get_builtin_value(CodeGen *codegen, const char *name) { - Buf *buf_name = buf_create_from_str(name); - - ScopeDecls *builtin_scope = get_container_scope(codegen->std_builtin_import); - Tld *tld = find_container_decl(codegen, builtin_scope, buf_name); - assert(tld != nullptr); - resolve_top_level_decl(codegen, tld, nullptr, false); - assert(tld->id == TldIdVar && tld->resolution == TldResolutionOk); - TldVar *tld_var = (TldVar *)tld; - ZigValue *var_value = tld_var->var->const_value; - assert(var_value != nullptr); - - buf_destroy(buf_name); - return var_value; -} - -ZigType *get_builtin_type(CodeGen *codegen, const char *name) { - ZigValue *type_val = get_builtin_value(codegen, name); - assert(type_val->type->id == ZigTypeIdMetaType); - return type_val->data.x_type; -} - -bool type_is_global_error_set(ZigType *err_set_type) { - assert(err_set_type->id == ZigTypeIdErrorSet); - assert(!err_set_type->data.error_set.incomplete); - return err_set_type->data.error_set.err_count == UINT32_MAX; -} - -bool type_can_fail(ZigType *type_entry) { - return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet; -} - -bool fn_type_can_fail(FnTypeId *fn_type_id) { - return type_can_fail(fn_type_id->return_type); -} - -// ErrorNone - result pointer has the type -// ErrorOverflow - an integer primitive type has too large a bit width -// ErrorPrimitiveTypeNotFound - result pointer unchanged -Error get_primitive_type(CodeGen *g, Buf *name, ZigType **result) { - if (buf_len(name) >= 2) { - uint8_t first_c = buf_ptr(name)[0]; - if (first_c == 'i' || first_c == 'u') { - for (size_t i = 1; i < buf_len(name); i += 1) { - uint8_t c = buf_ptr(name)[i]; - if (c < '0' || c > '9') { - goto not_integer; - } - } - bool is_signed = (first_c == 'i'); - unsigned long int bit_count = strtoul(buf_ptr(name) + 1, nullptr, 10); - // strtoul returns ULONG_MAX on errors, so this comparison catches that as well. - if (bit_count >= 65536) return ErrorOverflow; - *result = get_int_type(g, is_signed, bit_count); - return ErrorNone; - } - } - -not_integer: - - auto primitive_table_entry = g->primitive_type_table.maybe_get(name); - if (primitive_table_entry == nullptr) - return ErrorPrimitiveTypeNotFound; - - *result = primitive_table_entry->value; - return ErrorNone; -} - -Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) { - size_t len; - const char *contents = stage2_fetch_file(&g->stage1, buf_ptr(resolved_path), buf_len(resolved_path), &len); - if (contents == nullptr) - return ErrorFileNotFound; - buf_init_from_mem(contents_buf, contents, len); - return ErrorNone; -} - -static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { - // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 - switch (ty_size) { - case 1: - case 2: - case 4: - case 8: - break; - case 16: - return (ty->id == ZigTypeIdVector) ? X64CABIClass_SSE : X64CABIClass_MEMORY; - default: - return X64CABIClass_MEMORY; - } - switch (ty->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdNull: - case ZigTypeIdUndefined: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdEnumLiteral: - zig_unreachable(); - - case ZigTypeIdFn: - case ZigTypeIdPointer: - case ZigTypeIdInt: - case ZigTypeIdBool: - case ZigTypeIdEnum: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdErrorSet: - case ZigTypeIdErrorUnion: - case ZigTypeIdStruct: - case ZigTypeIdUnion: - case ZigTypeIdOptional: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return X64CABIClass_INTEGER; - - case ZigTypeIdFloat: - case ZigTypeIdVector: - return X64CABIClass_SSE; - - case ZigTypeIdArray: - return X64CABIClass_Unknown; - } - zig_unreachable(); -} - -static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { - switch (ty->id) { - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdBool: - return X64CABIClass_INTEGER; - case ZigTypeIdFloat: - case ZigTypeIdVector: - return X64CABIClass_SSE; - case ZigTypeIdStruct: { - // "If the size of an object is larger than four eightbytes, or it contains unaligned - // fields, it has class MEMORY" - if (ty_size > 32) - return X64CABIClass_MEMORY; - if (ty->data.structure.layout != ContainerLayoutExtern) { - // TODO determine whether packed structs have any unaligned fields - return X64CABIClass_Unknown; - } - // "If the size of the aggregate exceeds two eightbytes and the first eight- - // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument - // is passed in memory." - if (ty_size > 16) { - // Zig doesn't support vectors and large fp registers yet, so this will always - // be memory. - return X64CABIClass_MEMORY; - } - // "If the size of the aggregate exceeds a single eightbyte, each is classified - // separately.". - // "If one of the classes is MEMORY, the whole argument is passed in memory" - X64CABIClass working_class = X64CABIClass_Unknown; - for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) { - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields[0]->type_entry); - if (field_class == X64CABIClass_Unknown) - return X64CABIClass_Unknown; - if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) { - working_class = field_class; - } - } - if (working_class == X64CABIClass_MEMORY) { - return X64CABIClass_MEMORY; - } - return X64CABIClass_AGG; - } - case ZigTypeIdUnion: { - // "If the size of an object is larger than four eightbytes, or it contains unaligned - // fields, it has class MEMORY" - if (ty_size > 32) - return X64CABIClass_MEMORY; - if (ty->data.unionation.layout != ContainerLayoutExtern) - return X64CABIClass_MEMORY; - // "If the size of the aggregate exceeds two eightbytes and the first eight- - // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument - // is passed in memory." - if (ty_size > 16) { - // Zig doesn't support vectors and large fp registers yet, so this will always - // be memory. - return X64CABIClass_MEMORY; - } - X64CABIClass working_class = X64CABIClass_Unknown; - for (uint32_t i = 0; i < ty->data.unionation.src_field_count; i += 1) { - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.unionation.fields->type_entry); - if (field_class == X64CABIClass_Unknown) - return X64CABIClass_Unknown; - if (i == 0 || field_class == X64CABIClass_MEMORY || field_class == X64CABIClass_INTEGER || working_class == X64CABIClass_SSE) { - working_class = field_class; - } - } - return working_class; - } - default: - return X64CABIClass_Unknown; - } -} - -X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { - Error err; - const size_t ty_size = type_size(g, ty); - - if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { - return type_windows_abi_x86_64_class(g, ty, ty_size); - } - - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return X64CABIClass_Unknown; - if (ptr_type != nullptr) - return X64CABIClass_INTEGER; - - if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) - { - X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size); - return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result; - } else { - return type_system_V_abi_x86_64_class(g, ty, ty_size); - } -} - -// NOTE this does not depend on x86_64 -Error type_is_c_abi_int(CodeGen *g, ZigType *ty, bool *result) { - if (ty->id == ZigTypeIdInt || - ty->id == ZigTypeIdFloat || - ty->id == ZigTypeIdBool || - ty->id == ZigTypeIdEnum || - ty->id == ZigTypeIdVoid || - ty->id == ZigTypeIdUnreachable) - { - *result = true; - return ErrorNone; - } - - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return err; - *result = ptr_type != nullptr; - return ErrorNone; -} - -bool type_is_c_abi_int_bail(CodeGen *g, ZigType *ty) { - Error err; - bool result; - if ((err = type_is_c_abi_int(g, ty, &result))) - codegen_report_errors_and_exit(g); - - return result; -} - -uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field) { - assert(struct_type->id == ZigTypeIdStruct); - if (struct_type->data.structure.layout != ContainerLayoutAuto) { - assert(type_is_resolved(struct_type, ResolveStatusSizeKnown)); - } - if (struct_type->data.structure.host_int_bytes == nullptr) - return 0; - return struct_type->data.structure.host_int_bytes[field->gen_index]; -} - -Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *const_val, ZigType *wanted_type) -{ - ZigValue ptr_val = {}; - ptr_val.special = ConstValSpecialStatic; - ptr_val.type = get_pointer_to_type(codegen, wanted_type, true); - ptr_val.data.x_ptr.mut = ConstPtrMutComptimeConst; - ptr_val.data.x_ptr.special = ConstPtrSpecialRef; - ptr_val.data.x_ptr.data.ref.pointee = const_val; - if (const_ptr_pointee(ira, codegen, &ptr_val, source_node) == nullptr) - return ErrorSemanticAnalyzeFail; - - return ErrorNone; -} - -const char *container_string(ContainerKind kind) { - switch (kind) { - case ContainerKindEnum: return "enum"; - case ContainerKindStruct: return "struct"; - case ContainerKindUnion: return "union"; - case ContainerKindOpaque: return "opaque"; - } - zig_unreachable(); -} - -bool ptr_allows_addr_zero(ZigType *ptr_type) { - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.allow_zero; - } else if (ptr_type->id == ZigTypeIdOptional) { - return true; - } - return false; -} - -Buf *type_bare_name(ZigType *type_entry) { - if (is_slice(type_entry)) { - return &type_entry->name; - } else if (is_container(type_entry)) { - return get_container_scope(type_entry)->bare_name; - } else { - return &type_entry->name; - } -} - -// TODO this will have to be more clever, probably using the full name -// and replacing '.' with '_' or something like that -Buf *type_h_name(ZigType *t) { - return type_bare_name(t); -} - -static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - if (type->data.structure.resolve_status >= wanted_resolve_status) return; - - ZigType *ptr_type = type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *child_type = ptr_type->data.pointer.child_type; - ZigType *usize_type = g->builtin_types.entry_usize; - - bool done = false; - if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero || - ptr_type->data.pointer.sentinel != nullptr) - { - ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); - - assertNoError(type_resolve(g, peer_slice_type, wanted_resolve_status)); - type->llvm_type = peer_slice_type->llvm_type; - type->llvm_di_type = peer_slice_type->llvm_di_type; - type->data.structure.resolve_status = peer_slice_type->data.structure.resolve_status; - done = true; - } - - // If the child type is []const T then we need to make sure the type ref - // and debug info is the same as if the child type were []T. - if (is_slice(child_type)) { - ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index]->type_entry; - assert(child_ptr_type->id == ZigTypeIdPointer); - if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero || - child_ptr_type->data.pointer.sentinel != nullptr) - { - ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; - ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type); - ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); - - assertNoError(type_resolve(g, peer_slice_type, wanted_resolve_status)); - type->llvm_type = peer_slice_type->llvm_type; - type->llvm_di_type = peer_slice_type->llvm_di_type; - type->data.structure.resolve_status = peer_slice_type->data.structure.resolve_status; - done = true; - } - } - - if (done) return; - - LLVMTypeRef usize_llvm_type = get_llvm_type(g, usize_type); - ZigLLVMDIType *usize_llvm_di_type = get_llvm_di_type(g, usize_type); - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - - if (type->data.structure.resolve_status < ResolveStatusLLVMFwdDecl) { - type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name)); - - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - type->data.structure.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - if (!type_has_bits(g, child_type)) { - LLVMTypeRef element_types[] = { - usize_llvm_type, - }; - LLVMStructSetBody(type->llvm_type, element_types, 1, false); - - uint64_t len_debug_size_in_bits = usize_type->size_in_bits; - uint64_t len_debug_align_in_bits = 8*usize_type->abi_align; - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0); - - uint64_t debug_size_in_bits = type->size_in_bits; - uint64_t debug_align_in_bits = 8*type->abi_align; - - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - ZigLLVM_DIFlags_Zero, - usize_llvm_di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 1, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.structure.resolve_status = ResolveStatusLLVMFull; - return; - } - - LLVMTypeRef element_types[2]; - element_types[slice_ptr_index] = get_llvm_type(g, ptr_type); - element_types[slice_len_index] = get_llvm_type(g, g->builtin_types.entry_usize); - if (type->data.structure.resolve_status >= wanted_resolve_status) return; - LLVMStructSetBody(type->llvm_type, element_types, 2, false); - - uint64_t ptr_debug_size_in_bits = ptr_type->size_in_bits; - uint64_t ptr_debug_align_in_bits = 8*ptr_type->abi_align; - uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0); - - uint64_t len_debug_size_in_bits = usize_type->size_in_bits; - uint64_t len_debug_align_in_bits = 8*usize_type->abi_align; - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1); - - uint64_t debug_size_in_bits = type->size_in_bits; - uint64_t debug_align_in_bits = 8*type->abi_align; - - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "ptr", di_file, line, - ptr_debug_size_in_bits, - ptr_debug_align_in_bits, - ptr_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_type)), - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - ZigLLVM_DIFlags_Zero, usize_llvm_di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.structure.resolve_status = ResolveStatusLLVMFull; -} - -static LLVMTypeRef get_llvm_type_of_n_bytes(unsigned byte_size) { - return byte_size == 1 ? - LLVMInt8Type() : LLVMArrayType(LLVMInt8Type(), byte_size); -} - -static LLVMTypeRef llvm_int_for_size(size_t size) { - if (size > 4) { - return LLVMInt64Type(); - } else if (size > 2) { - return LLVMInt32Type(); - } else if (size == 2) { - return LLVMInt16Type(); - } else { - return LLVMInt8Type(); - } -} - -static LLVMTypeRef llvm_sse_for_size(size_t size) { - if (size > 4) - return LLVMDoubleType(); - else - return LLVMFloatType(); -} - -// Since it's not possible to control calling convention or register -// allocation in LLVM, clang seems to use intermediate types to manipulate -// LLVM into doing the right thing. It uses a float to force SSE registers, -// and a struct when 2 registers must be used. Some examples: -// { f32 } -> float -// { f32, i32 } -> { float, i32 } -// { i32, i32, f32 } -> { i64, float } -// -// The implementation below does not match clang 1:1. For instance, clang -// uses `<2x float>` while we generate `double`. There's a lot more edge -// cases and complexity when converting back and forth in clang though, -// so below is the simplest implementation that passes all tests. -static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) { - size_t ty_size = type_size(g, ty); - LLVMTypeRef abi_type; - switch (ty->id) { - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdBool: - abi_type = llvm_int_for_size(ty_size); - break; - case ZigTypeIdFloat: - case ZigTypeIdVector: - abi_type = llvm_sse_for_size(ty_size); - break; - case ZigTypeIdStruct: { - uint32_t eightbyte_index = 0; - size_t type_sizes[] = {0, 0}; - X64CABIClass type_classes[] = {X64CABIClass_Unknown, X64CABIClass_Unknown}; - for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) { - if (ty->data.structure.fields[i]->offset >= 8) { - eightbyte_index = 1; - } - ZigType *field_ty = ty->data.structure.fields[i]->type_entry; - X64CABIClass field_class = type_c_abi_x86_64_class(g, field_ty); - - if (field_class == X64CABIClass_INTEGER) { - type_classes[eightbyte_index] = X64CABIClass_INTEGER; - } else if (type_classes[eightbyte_index] == X64CABIClass_Unknown) { - type_classes[eightbyte_index] = field_class; - } - if (field_ty->abi_size > 8) { - assert(eightbyte_index == 0); - type_sizes[0] = 8; - type_sizes[1] = field_ty->abi_size - 8; - type_classes[1] = type_classes[0]; - eightbyte_index = 1; - } else { - type_sizes[eightbyte_index] += field_ty->abi_size; - } - } - - LLVMTypeRef return_elem_types[] = { - LLVMVoidType(), - LLVMVoidType(), - }; - for (uint32_t i = 0; i <= eightbyte_index; i += 1) { - if (type_classes[i] == X64CABIClass_INTEGER) { - return_elem_types[i] = llvm_int_for_size(type_sizes[i]); - } else { - return_elem_types[i] = llvm_sse_for_size(type_sizes[i]); - } - } - if (eightbyte_index == 0) { - abi_type = return_elem_types[0]; - } else { - abi_type = LLVMStructType(return_elem_types, 2, false); - } - break; - } - case ZigTypeIdUnion: - default: - // currently unreachable - zig_panic("TODO: support C ABI unions"); - } - ty->llvm_c_abi_type = abi_type; - return ErrorNone; -} - -static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status, - ZigType *async_frame_type) -{ - assert(struct_type->id == ZigTypeIdStruct); - assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid); - assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown); - assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); - if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return; - - AstNode *decl_node = struct_type->data.structure.decl_node; - ZigLLVMDIFile *di_file; - ZigLLVMDIScope *di_scope; - unsigned line; - if (decl_node != nullptr) { - Scope *scope = &struct_type->data.structure.decls_scope->base; - ZigType *import = get_scope_import(scope); - di_file = import->data.structure.root_struct->di_file; - di_scope = ZigLLVMFileToScope(di_file); - line = node_line_onebased(decl_node); - } else { - di_file = nullptr; - di_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - line = 0; - } - - if (struct_type->data.structure.resolve_status < ResolveStatusLLVMFwdDecl) { - struct_type->llvm_type = type_has_bits(g, struct_type) ? - LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&struct_type->name)) : LLVMVoidType(); - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - struct_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&struct_type->name), - di_scope, di_file, line); - - struct_type->data.structure.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) { - struct_type->data.structure.llvm_full_type_queue_index = g->type_resolve_stack.length; - g->type_resolve_stack.append(struct_type); - return; - } else { - struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; - } - } - - size_t field_count = struct_type->data.structure.src_field_count; - // Every field could potentially have a generated padding field after it. - LLVMTypeRef *element_types = heap::c_allocator.allocate(field_count * 2); - - bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - size_t packed_bits_offset = 0; - size_t first_packed_bits_offset_misalign = SIZE_MAX; - size_t debug_field_count = 0; - - // trigger all the recursive get_llvm_type calls - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - if (!type_has_bits(g, field_type)) - continue; - (void)get_llvm_type(g, field_type); - if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return; - } - - size_t gen_field_index = 0; - - // Calculate what LLVM thinks the ABI align of the struct will be. We do this to avoid - // inserting padding bytes where LLVM would do it automatically. - size_t llvm_struct_abi_align = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - if (field->is_comptime || !type_has_bits(g, field_type)) - continue; - LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type); - size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type); - llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align); - } - - ZigType* last_packed_field_type = nullptr; - - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - - if (field->is_comptime || !type_has_bits(g, field_type)) { - field->gen_index = SIZE_MAX; - continue; - } - - if (packed) { - last_packed_field_type = field_type; - size_t field_size_in_bits = type_size_bits(g, field_type); - size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - // this field is not byte-aligned; it is part of the previous field with a bit offset - - size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); - if (full_abi_size * 8 == full_bit_count) { - // next field recovers ABI alignment - element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size); - gen_field_index += 1; - first_packed_bits_offset_misalign = SIZE_MAX; - } - } else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) { - first_packed_bits_offset_misalign = packed_bits_offset; - } else { - // This is a byte-aligned field (both start and end) in a packed struct. - element_types[gen_field_index] = get_llvm_type(g, field_type); - assert(get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) == - LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index])); - gen_field_index += 1; - } - packed_bits_offset = next_packed_bits_offset; - } else { - LLVMTypeRef llvm_type; - if (i == 0 && async_frame_type != nullptr) { - assert(async_frame_type->id == ZigTypeIdFnFrame); - assert(field_type->id == ZigTypeIdFn); - resolve_llvm_types_fn(g, async_frame_type->data.frame.fn); - - const unsigned addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - llvm_type = LLVMPointerType(async_frame_type->data.frame.fn->raw_type_ref, addrspace); - } else { - llvm_type = get_llvm_type(g, field_type); - } - element_types[gen_field_index] = llvm_type; - field->gen_index = gen_field_index; - gen_field_index += 1; - - // find the next non-zero-byte field for offset calculations - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (type_has_bits(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)) - break; - } - size_t next_abi_align; - if (next_src_field_index == field_count) { - next_abi_align = struct_type->abi_align; - } else { - if (struct_type->data.structure.fields[next_src_field_index]->align == 0) { - next_abi_align = struct_type->data.structure.fields[next_src_field_index]->type_entry->abi_align; - } else { - next_abi_align = struct_type->data.structure.fields[next_src_field_index]->align; - } - } - size_t llvm_next_abi_align = (next_src_field_index == field_count) ? - llvm_struct_abi_align : - LLVMABIAlignmentOfType(g->target_data_ref, - get_llvm_type(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)); - - size_t next_offset = next_field_offset(field->offset, struct_type->abi_align, - field_type->abi_size, next_abi_align); - size_t llvm_next_offset = next_field_offset(field->offset, llvm_struct_abi_align, - LLVMABISizeOfType(g->target_data_ref, llvm_type), llvm_next_abi_align); - - assert(next_offset >= llvm_next_offset); - if (next_offset > llvm_next_offset) { - size_t pad_bytes = next_offset - (field->offset + LLVMABISizeOfType(g->target_data_ref, llvm_type)); - if (pad_bytes != 0) { - LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes); - element_types[gen_field_index] = pad_llvm_type; - gen_field_index += 1; - } - } - } - debug_field_count += 1; - } - if (!packed) { - struct_type->data.structure.gen_field_count = gen_field_index; - } - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1); - if (last_packed_field_type->size_in_bits == full_bit_count && last_packed_field_type->id != ZigTypeIdInt && last_packed_field_type->id != ZigTypeIdEnum) { - // If there is only one field that is misaligned and it is a custom type just use it - element_types[gen_field_index] = get_llvm_type(g, last_packed_field_type); - assert(full_abi_size == LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index])); - } else { - // Otherwise represent it as array of proper number of bytes in LLVM - element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size); - } - gen_field_index += 1; - } - - if (type_has_bits(g, struct_type)) { - assert(struct_type->data.structure.gen_field_count == gen_field_index); - LLVMStructSetBody(struct_type->llvm_type, element_types, - (unsigned)struct_type->data.structure.gen_field_count, packed); - } - - ZigLLVMDIType **di_element_types = heap::c_allocator.allocate(debug_field_count); - size_t debug_field_index = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - //fprintf(stderr, "%s at gen index %zu\n", buf_ptr(field->name), field->gen_index); - - size_t gen_field_index = field->gen_index; - if (gen_field_index == SIZE_MAX) { - continue; - } - - ZigType *field_type = field->type_entry; - - // if the field is a function, actually the debug info should be a pointer. - ZigLLVMDIType *field_di_type; - if (field_type->id == ZigTypeIdFn) { - ZigType *field_ptr_type = get_pointer_to_type(g, field_type, true); - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type)); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type)); - field_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, field_type), - debug_size_in_bits, debug_align_in_bits, buf_ptr(&field_ptr_type->name)); - } else { - field_di_type = get_llvm_di_type(g, field_type); - } - - uint64_t debug_size_in_bits; - uint64_t debug_align_in_bits; - uint64_t debug_offset_in_bits; - if (packed) { - debug_size_in_bits = field->type_entry->size_in_bits; - debug_align_in_bits = 8 * field->type_entry->abi_align; - debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host; - } else { - debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits); - debug_align_in_bits = 8 * field_type->abi_align; - debug_offset_in_bits = 8 * field->offset; - } - unsigned line; - if (decl_node != nullptr) { - AstNode *field_node = field->decl_node; - line = node_line_onebased(field_node); - } else { - line = 0; - } - di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(field->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - debug_offset_in_bits, - ZigLLVM_DIFlags_Zero, field_di_type); - assert(di_element_types[debug_field_index]); - debug_field_index += 1; - } - - uint64_t debug_size_in_bits = 8*get_store_size_bytes(struct_type->size_in_bits); - uint64_t debug_align_in_bits = 8*struct_type->abi_align; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - di_scope, - buf_ptr(&struct_type->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, struct_type->llvm_di_type, replacement_di_type); - struct_type->llvm_di_type = replacement_di_type; - struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; - if (struct_type->data.structure.llvm_full_type_queue_index != SIZE_MAX) { - ZigType *last = g->type_resolve_stack.last(); - assert(last->id == ZigTypeIdStruct); - last->data.structure.llvm_full_type_queue_index = struct_type->data.structure.llvm_full_type_queue_index; - g->type_resolve_stack.swap_remove(struct_type->data.structure.llvm_full_type_queue_index); - struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; - } - - if (struct_type->abi_size <= 16 && - (struct_type->data.structure.layout == ContainerLayoutExtern || - struct_type->data.structure.layout == ContainerLayoutPacked)) - { - resolve_llvm_c_abi_type(g, struct_type); - } -} - -// This is to be used instead of void for debug info types, to avoid tripping -// Assertion `!isa(Scope) && "shouldn't make a namespace scope for a type"' -// when targeting CodeView (Windows). -static ZigLLVMDIType *make_empty_namespace_llvm_di_type(CodeGen *g, ZigType *import, const char *name, - AstNode *decl_node) -{ - uint64_t debug_size_in_bits = 0; - uint64_t debug_align_in_bits = 0; - ZigLLVMDIType **di_element_types = nullptr; - size_t debug_field_count = 0; - return ZigLLVMCreateDebugStructType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - name, - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); -} - -static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { - assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown); - if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return; - - Scope *scope = &enum_type->data.enumeration.decls_scope->base; - ZigType *import = get_scope_import(scope); - AstNode *decl_node = enum_type->data.enumeration.decl_node; - - if (!type_has_bits(g, enum_type)) { - enum_type->llvm_type = g->builtin_types.entry_void->llvm_type; - enum_type->llvm_di_type = make_empty_namespace_llvm_di_type(g, import, buf_ptr(&enum_type->name), - decl_node); - enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; - return; - } - - uint32_t field_count = enum_type->data.enumeration.src_field_count; - - assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr); - ZigLLVMDIEnumerator **di_enumerators = heap::c_allocator.allocate(field_count); - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i]; - - // https://github.com/ziglang/zig/issues/645 - di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name), - bigint_as_signed(&enum_field->value), false); - } - - ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; - enum_type->llvm_type = get_llvm_type(g, tag_int_type); - - // create debug type for tag - uint64_t tag_debug_size_in_bits = 8*tag_int_type->abi_size; - uint64_t tag_debug_align_in_bits = 8*tag_int_type->abi_align; - ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - tag_debug_size_in_bits, - tag_debug_align_in_bits, - di_enumerators, field_count, - get_llvm_di_type(g, tag_int_type), ""); - - enum_type->llvm_di_type = tag_di_type; - enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { - if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; - - bool packed = (union_type->data.unionation.layout == ContainerLayoutPacked); - Scope *scope = &union_type->data.unionation.decls_scope->base; - ZigType *import = get_scope_import(scope); - - TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; - ZigType *tag_type = union_type->data.unionation.tag_type; - uint32_t gen_field_count = union_type->data.unionation.gen_field_count; - if (gen_field_count == 0) { - if (tag_type == nullptr) { - union_type->llvm_type = g->builtin_types.entry_void->llvm_type; - union_type->llvm_di_type = make_empty_namespace_llvm_di_type(g, import, buf_ptr(&union_type->name), - union_type->data.unionation.decl_node); - } else { - union_type->llvm_type = get_llvm_type(g, tag_type); - union_type->llvm_di_type = get_llvm_di_type(g, tag_type); - } - - union_type->data.unionation.gen_union_index = SIZE_MAX; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; - return; - } - - AstNode *decl_node = union_type->data.unionation.decl_node; - - if (union_type->data.unionation.resolve_status < ResolveStatusLLVMFwdDecl) { - union_type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&union_type->name)); - unsigned line = decl_node ? node_line_onebased(decl_node) : 0; - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - union_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&union_type->name), - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - import->data.structure.root_struct->di_file, line); - - union_type->data.unionation.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - ZigLLVMDIType **union_inner_di_types = heap::c_allocator.allocate(gen_field_count); - uint32_t field_count = union_type->data.unionation.src_field_count; - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (!type_has_bits(g, union_field->type_entry)) - continue; - - ZigLLVMDIType *field_di_type = get_llvm_di_type(g, union_field->type_entry); - if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; - - uint64_t store_size_in_bits = union_field->type_entry->size_in_bits; - uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align; - AstNode *field_node = union_field->decl_node; - union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), - import->data.structure.root_struct->di_file, node_line_onebased(field_node), - store_size_in_bits, - abi_align_in_bits, - 0, - ZigLLVM_DIFlags_Zero, field_di_type); - - } - - if (tag_type == nullptr || !type_has_bits(g, tag_type)) { - assert(most_aligned_union_member != nullptr); - - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; - if (padding_bytes > 0) { - ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); - LLVMTypeRef union_element_types[] = { - most_aligned_union_member->type_entry->llvm_type, - get_llvm_type(g, padding_array), - }; - LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, packed); - } else { - LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->type_entry->llvm_type, 1, packed); - } - union_type->data.unionation.union_llvm_type = union_type->llvm_type; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.gen_union_index = SIZE_MAX; - - // create debug type for union - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - union_type->data.unionation.union_abi_size * 8, - most_aligned_union_member->align * 8, - ZigLLVM_DIFlags_Zero, union_inner_di_types, - gen_field_count, 0, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, union_type->llvm_di_type, replacement_di_type); - union_type->llvm_di_type = replacement_di_type; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; - return; - } - - LLVMTypeRef union_type_ref; - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; - if (padding_bytes == 0) { - union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry); - } else { - ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); - LLVMTypeRef union_element_types[] = { - get_llvm_type(g, most_aligned_union_member->type_entry), - get_llvm_type(g, padding_array), - }; - union_type_ref = LLVMStructType(union_element_types, 2, false); - } - union_type->data.unionation.union_llvm_type = union_type_ref; - - LLVMTypeRef root_struct_element_types[2]; - root_struct_element_types[union_type->data.unionation.gen_tag_index] = get_llvm_type(g, tag_type); - root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref; - LLVMStructSetBody(union_type->llvm_type, root_struct_element_types, 2, packed); - - // create debug type for union - ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, - ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); - - uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, - union_type->data.unionation.gen_union_index); - uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, - union_type->data.unionation.gen_tag_index); - - ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - most_aligned_union_member->type_entry->size_in_bits, - 8*most_aligned_union_member->align, - union_offset_in_bits, - ZigLLVM_DIFlags_Zero, union_di_type); - - uint64_t tag_debug_size_in_bits = tag_type->size_in_bits; - uint64_t tag_debug_align_in_bits = 8*tag_type->abi_align; - - ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "tag", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - tag_debug_size_in_bits, - tag_debug_align_in_bits, - tag_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, tag_type)); - - ZigLLVMDIType *di_root_members[2]; - di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type; - di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type; - - uint64_t debug_size_in_bits = union_type->size_in_bits; - uint64_t debug_align_in_bits = 8*union_type->abi_align; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, nullptr, di_root_members, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, union_type->llvm_di_type, replacement_di_type); - union_type->llvm_di_type = replacement_di_type; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - if (type->llvm_di_type != nullptr) return; - - if (resolve_pointer_zero_bits(g, type) != ErrorNone) - zig_unreachable(); - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - ZigType *elem_type = type->data.pointer.child_type; - - if (type->data.pointer.is_const || type->data.pointer.is_volatile || - type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle || - type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero || - type->data.pointer.vector_index != VECTOR_INDEX_NONE || type->data.pointer.sentinel != nullptr) - { - assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); - ZigType *peer_type; - if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { - peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, - PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, - VECTOR_INDEX_NONE, nullptr, nullptr); - } else { - uint32_t host_vec_len = type->data.pointer.host_int_bytes; - ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); - peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); - } - type->llvm_type = get_llvm_type(g, peer_type); - type->llvm_di_type = get_llvm_di_type(g, peer_type); - assertNoError(type_resolve(g, elem_type, wanted_resolve_status)); - return; - } - - if (type->data.pointer.host_int_bytes == 0) { - assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); - type->llvm_type = LLVMPointerType(elem_type->llvm_type, 0); - uint64_t debug_size_in_bits = 8*get_store_size_bytes(type->size_in_bits); - uint64_t debug_align_in_bits = 8*type->abi_align; - type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type, - debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name)); - assertNoError(type_resolve(g, elem_type, wanted_resolve_status)); - } else { - ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8); - LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type); - type->llvm_type = LLVMPointerType(host_int_llvm_type, 0); - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, host_int_llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, host_int_llvm_type); - type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, host_int_type), - debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name)); - } -} - -static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - unsigned dwarf_tag; - if (type->data.integral.is_signed) { - if (type->size_in_bits == 8) { - dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char(); - } else { - dwarf_tag = ZigLLVMEncoding_DW_ATE_signed(); - } - } else { - if (type->size_in_bits == 8) { - dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char(); - } else { - dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned(); - } - } - - type->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&type->name), - type->size_in_bits, dwarf_tag); - type->llvm_type = LLVMIntType(type->size_in_bits); -} - -static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - assert(type->id == ZigTypeIdOptional); - assert(type->data.maybe.resolve_status != ResolveStatusInvalid); - assert(type->data.maybe.resolve_status >= ResolveStatusSizeKnown); - if (type->data.maybe.resolve_status >= wanted_resolve_status) return; - - LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool); - ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool); - - ZigType *child_type = type->data.maybe.child_type; - if (!type_has_bits(g, child_type)) { - type->llvm_type = bool_llvm_type; - type->llvm_di_type = bool_llvm_di_type; - type->data.maybe.resolve_status = ResolveStatusLLVMFull; - return; - } - - if (type_is_nonnull_ptr(g, child_type) || child_type->id == ZigTypeIdErrorSet) { - type->llvm_type = get_llvm_type(g, child_type); - type->llvm_di_type = get_llvm_di_type(g, child_type); - type->data.maybe.resolve_status = ResolveStatusLLVMFull; - return; - } - - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - - if (type->data.maybe.resolve_status < ResolveStatusLLVMFwdDecl) { - type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name)); - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - type->data.maybe.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type); - if (type->data.maybe.resolve_status >= wanted_resolve_status) return; - - LLVMTypeRef elem_types[] = { - get_llvm_type(g, child_type), - LLVMInt1Type(), - }; - LLVMStructSetBody(type->llvm_type, elem_types, 2, false); - - uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_child_index); - uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_null_index); - - ZigLLVMDIType *di_element_types[2]; - di_element_types[maybe_child_index] = - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "val", di_file, line, - 8 * child_type->abi_size, - 8 * child_type->abi_align, - val_offset_in_bits, - ZigLLVM_DIFlags_Zero, child_llvm_di_type); - di_element_types[maybe_null_index] = - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "maybe", di_file, line, - 8*g->builtin_types.entry_bool->abi_size, - 8*g->builtin_types.entry_bool->abi_align, - maybe_offset_in_bits, - ZigLLVM_DIFlags_Zero, bool_llvm_di_type); - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, 8 * type->abi_size, 8 * type->abi_align, ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.maybe.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - ZigType *payload_type = type->data.error_union.payload_type; - ZigType *err_set_type = type->data.error_union.err_set_type; - - if (!type_has_bits(g, payload_type)) { - assert(type_has_bits(g, err_set_type)); - type->llvm_type = get_llvm_type(g, err_set_type); - type->llvm_di_type = get_llvm_di_type(g, err_set_type); - } else if (!type_has_bits(g, err_set_type)) { - type->llvm_type = get_llvm_type(g, payload_type); - type->llvm_di_type = get_llvm_di_type(g, payload_type); - } else { - LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type); - LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type); - LLVMTypeRef elem_types[3]; - elem_types[err_union_err_index] = err_set_llvm_type; - elem_types[err_union_payload_index] = payload_llvm_type; - - type->llvm_type = LLVMStructType(elem_types, 2, false); - if (LLVMABISizeOfType(g->target_data_ref, type->llvm_type) != type->abi_size) { - // we need to do our own padding - type->data.error_union.pad_llvm_type = LLVMArrayType(LLVMInt8Type(), type->data.error_union.pad_bytes); - elem_types[2] = type->data.error_union.pad_llvm_type; - type->llvm_type = LLVMStructType(elem_types, 3, false); - } - - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_llvm_type); - uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_llvm_type); - uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, err_union_err_index); - - uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_llvm_type); - uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_llvm_type); - uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, - err_union_payload_index); - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type); - - ZigLLVMDIType *di_element_types[2]; - di_element_types[err_union_err_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(type->llvm_di_type), - "tag", di_file, line, - tag_debug_size_in_bits, - tag_debug_align_in_bits, - tag_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type)); - di_element_types[err_union_payload_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(type->llvm_di_type), - "value", di_file, line, - value_debug_size_in_bits, - value_debug_align_in_bits, - value_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type)); - - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - } -} - -static void resolve_llvm_types_array(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - ZigType *elem_type = type->data.array.child_type; - - uint64_t extra_len_from_sentinel = (type->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = type->data.array.len + extra_len_from_sentinel; - // TODO https://github.com/ziglang/zig/issues/1424 - type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len); - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type); - - type->llvm_di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits, - debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)full_len); -} - -static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { - if (fn_type->llvm_di_type != nullptr) return; - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - bool first_arg_return = want_first_arg_sret(g, fn_type_id); - bool is_async = fn_type_id->cc == CallingConventionAsync; - bool is_c_abi = !calling_convention_allows_zig_types(fn_type_id->cc); - bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id); - // +1 for maybe making the first argument the return value - // +1 for maybe first argument the error return trace - // +2 for maybe arguments async allocator and error code pointer - ZigList gen_param_types = {}; - // +1 because 0 is the return type and - // +1 for maybe making first arg ret val and - // +1 for maybe first argument the error return trace - // +2 for maybe arguments async allocator and error code pointer - ZigList param_di_types = {}; - ZigType *gen_return_type; - if (is_async) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - } else if (!type_has_bits(g, fn_type_id->return_type)) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - } else if (first_arg_return) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); - gen_param_types.append(get_llvm_type(g, gen_type)); - param_di_types.append(get_llvm_di_type(g, gen_type)); - } else { - gen_return_type = fn_type_id->return_type; - param_di_types.append(get_llvm_di_type(g, gen_return_type)); - } - fn_type->data.fn.gen_return_type = gen_return_type; - - if (prefix_arg_error_return_trace && !is_async) { - ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - gen_param_types.append(get_llvm_type(g, gen_type)); - param_di_types.append(get_llvm_di_type(g, gen_type)); - } - if (is_async) { - fn_type->data.fn.gen_param_info = heap::c_allocator.allocate(2); - - ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type); - gen_param_types.append(get_llvm_type(g, frame_type)); - param_di_types.append(get_llvm_di_type(g, frame_type)); - - fn_type->data.fn.gen_param_info[0].src_index = 0; - fn_type->data.fn.gen_param_info[0].gen_index = 0; - fn_type->data.fn.gen_param_info[0].type = frame_type; - - gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize)); - param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize)); - - fn_type->data.fn.gen_param_info[1].src_index = 1; - fn_type->data.fn.gen_param_info[1].gen_index = 1; - fn_type->data.fn.gen_param_info[1].type = g->builtin_types.entry_usize; - } else { - fn_type->data.fn.gen_param_info = heap::c_allocator.allocate(fn_type_id->param_count); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; - ZigType *type_entry = src_param_info->type; - FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; - - gen_param_info->src_index = i; - gen_param_info->gen_index = SIZE_MAX; - - if (is_c_abi || !type_has_bits(g, type_entry)) - continue; - - ZigType *gen_type; - if (handle_is_ptr(g, type_entry)) { - gen_type = get_pointer_to_type(g, type_entry, true); - gen_param_info->is_byval = true; - } else { - gen_type = type_entry; - } - gen_param_info->gen_index = gen_param_types.length; - gen_param_info->type = gen_type; - gen_param_types.append(get_llvm_type(g, gen_type)); - - param_di_types.append(get_llvm_di_type(g, gen_type)); - } - } - - if (is_c_abi) { - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdTypes; - fn_walk.data.types.param_di_types = ¶m_di_types; - fn_walk.data.types.gen_param_types = &gen_param_types; - walk_function_params(g, fn_type, &fn_walk); - } - - fn_type->data.fn.gen_param_count = gen_param_types.length; - - for (size_t i = 0; i < gen_param_types.length; i += 1) { - assert(gen_param_types.items[i] != nullptr); - } - - if (!first_arg_return && fn_returns_c_abi_small_struct(fn_type_id)) { - fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_c_abi_type(g, gen_return_type), - gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); - } else { - fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), - gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); - } - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, fn_addrspace); - fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); - fn_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type, - LLVMStoreSizeOfType(g->target_data_ref, fn_type->llvm_type), - LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), ""); - - gen_param_types.deinit(); - param_di_types.deinit(); -} - -void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) { - Error err; - if (fn->raw_di_type != nullptr) return; - - ZigType *fn_type = fn->type_entry; - if (!fn_is_async(fn)) { - resolve_llvm_types_fn_type(g, fn_type); - fn->raw_type_ref = fn_type->data.fn.raw_type_ref; - fn->raw_di_type = fn_type->data.fn.raw_di_type; - return; - } - - ZigType *gen_return_type = g->builtin_types.entry_void; - ZigList param_di_types = {}; - ZigList gen_param_types = {}; - // first "parameter" is return value - param_di_types.append(nullptr); - - ZigType *frame_type = get_fn_frame_type(g, fn); - ZigType *ptr_type = get_pointer_to_type(g, frame_type, false); - if ((err = type_resolve(g, ptr_type, ResolveStatusLLVMFwdDecl))) - zig_unreachable(); - gen_param_types.append(ptr_type->llvm_type); - param_di_types.append(ptr_type->llvm_di_type); - - // this parameter is used to pass the result pointer when await completes - gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize)); - param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize)); - - fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), - gen_param_types.items, gen_param_types.length, false); - fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); - - param_di_types.deinit(); - gen_param_types.deinit(); -} - -static void resolve_llvm_types_anyerror(CodeGen *g) { - ZigType *entry = g->builtin_types.entry_global_error_set; - entry->llvm_type = get_llvm_type(g, g->err_tag_type); - ZigList err_enumerators = {}; - // reserve index 0 to indicate no error - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0, false)); - for (size_t i = 1; i < g->errors_by_index.length; i += 1) { - ErrorTableEntry *error_entry = g->errors_by_index.at(i); - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&error_entry->name), i, false)); - } - - // create debug type for error sets - uint64_t tag_debug_size_in_bits = g->err_tag_type->size_in_bits; - uint64_t tag_debug_align_in_bits = 8*g->err_tag_type->abi_align; - ZigLLVMDIFile *err_set_di_file = nullptr; - entry->llvm_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, - ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&entry->name), - err_set_di_file, 0, - tag_debug_size_in_bits, - tag_debug_align_in_bits, - err_enumerators.items, err_enumerators.length, - get_llvm_di_type(g, g->err_tag_type), ""); - - err_enumerators.deinit(); -} - -static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { - Error err; - if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) - zig_unreachable(); - - ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr; - resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type); - frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; - frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type; -} - -static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, ResolveStatus wanted_resolve_status) { - if (any_frame_type->llvm_di_type != nullptr) return; - - Buf *name = buf_sprintf("(%s header)", buf_ptr(&any_frame_type->name)); - LLVMTypeRef frame_header_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name)); - any_frame_type->llvm_type = LLVMPointerType(frame_header_type, 0); - any_frame_type->data.any_frame.struct_llvm_ty = frame_header_type; - - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - ZigLLVMDIFile *di_file = nullptr; - ZigLLVMDIScope *di_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - unsigned line = 0; - ZigLLVMDIType *frame_header_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(name), di_scope, di_file, line); - any_frame_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, frame_header_di_type, - 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name)); - - LLVMTypeRef llvm_void = LLVMVoidType(); - LLVMTypeRef arg_types[] = {any_frame_type->llvm_type, g->builtin_types.entry_usize->llvm_type}; - LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, arg_types, 2, false); - LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize); - ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize); - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - - ZigType *result_type = any_frame_type->data.any_frame.result_type; - ZigType *ptr_result_type = (result_type == nullptr) ? nullptr : get_pointer_to_type(g, result_type, false); - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - LLVMTypeRef ptr_fn_llvm_type = LLVMPointerType(fn_type, fn_addrspace); - if (result_type == nullptr) { - g->any_frame_header_llvm_ty = frame_header_type; - g->anyframe_fn_type = fn_type; - } - - ZigList field_types = {}; - ZigList di_element_types = {}; - - // label (grep this): [fn_frame_struct_layout] - field_types.append(ptr_fn_llvm_type); // fn_ptr - field_types.append(usize_type_ref); // resume_index - field_types.append(usize_type_ref); // awaiter - - bool have_result_type = result_type != nullptr && type_has_bits(g, result_type); - if (have_result_type) { - field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_callee - field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_awaiter - field_types.append(get_llvm_type(g, result_type)); // result - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); - field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_callee - field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_awaiter - } - } - LLVMStructSetBody(frame_header_type, field_types.items, field_types.length, false); - - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "fn_ptr", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "resume_index", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - - if (have_result_type) { - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_callee", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, result_type))); - - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_callee", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); - } - }; - - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, buf_ptr(name), - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, frame_header_type), - 8*LLVMABIAlignmentOfType(g->target_data_ref, frame_header_type), - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types.items, di_element_types.length, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, frame_header_di_type, replacement_di_type); - - field_types.deinit(); - di_element_types.deinit(); -} - -static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - assert(wanted_resolve_status > ResolveStatusSizeKnown); - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - zig_unreachable(); - case ZigTypeIdFloat: - case ZigTypeIdOpaque: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - assert(type->llvm_di_type != nullptr); - return; - case ZigTypeIdStruct: - if (type->data.structure.special == StructSpecialSlice) - return resolve_llvm_types_slice(g, type, wanted_resolve_status); - else - return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); - case ZigTypeIdEnum: - return resolve_llvm_types_enum(g, type, wanted_resolve_status); - case ZigTypeIdUnion: - return resolve_llvm_types_union(g, type, wanted_resolve_status); - case ZigTypeIdPointer: - return resolve_llvm_types_pointer(g, type, wanted_resolve_status); - case ZigTypeIdInt: - return resolve_llvm_types_integer(g, type); - case ZigTypeIdOptional: - return resolve_llvm_types_optional(g, type, wanted_resolve_status); - case ZigTypeIdErrorUnion: - return resolve_llvm_types_error_union(g, type); - case ZigTypeIdArray: - return resolve_llvm_types_array(g, type); - case ZigTypeIdFn: - return resolve_llvm_types_fn_type(g, type); - case ZigTypeIdErrorSet: { - if (type->llvm_di_type != nullptr) return; - - if (g->builtin_types.entry_global_error_set->llvm_type == nullptr) { - resolve_llvm_types_anyerror(g); - } - type->llvm_type = g->builtin_types.entry_global_error_set->llvm_type; - type->llvm_di_type = g->builtin_types.entry_global_error_set->llvm_di_type; - return; - } - case ZigTypeIdVector: { - if (type->llvm_di_type != nullptr) return; - - type->llvm_type = LLVMVectorType(get_llvm_type(g, type->data.vector.elem_type), - type->data.vector.len); - - type->llvm_di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, - 8 * type->abi_size, - 8 * type->abi_align, - get_llvm_di_type(g, type->data.vector.elem_type), - type->data.vector.len); - return; - } - case ZigTypeIdFnFrame: - return resolve_llvm_types_async_frame(g, type, wanted_resolve_status); - case ZigTypeIdAnyFrame: - return resolve_llvm_types_any_frame(g, type, wanted_resolve_status); - } - zig_unreachable(); -} - -LLVMTypeRef get_llvm_c_abi_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type)); - assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type)); - return type->llvm_c_abi_type; -} - -LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type)); - assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type)); - return type->llvm_type; -} - -ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - return type->llvm_di_type; -} - -void src_assert_impl(bool ok, AstNode *source_node, char const *file, unsigned int line) { - if (ok) return; - if (source_node == nullptr) { - fprintf(stderr, "when analyzing (unknown source location) "); - } else { - RootStruct *root_struct = source_node->owner->data.structure.root_struct; - fprintf(stderr, "when analyzing %s:%u:%u ", buf_ptr(root_struct->path), - node_line_onebased(source_node), node_column_onebased(source_node)); - } - fprintf(stderr, "in compiler source at %s:%u: ", file, line); - const char *msg = "assertion failed. This is a bug in the Zig compiler."; - stage2_panic(msg, strlen(msg)); -} - -Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, - ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path) -{ - Error err; - - Buf *search_dir; - ZigPackage *cur_scope_pkg = source_import->data.structure.root_struct->package; - assert(cur_scope_pkg); - ZigPackage *target_package; - auto package_entry = cur_scope_pkg->package_table.maybe_get(import_target_str); - SourceKind source_kind; - if (package_entry) { - target_package = package_entry->value; - *out_import_target_path = &target_package->root_src_path; - search_dir = &target_package->root_src_dir; - source_kind = SourceKindPkgMain; - } else { - // try it as a filename - target_package = cur_scope_pkg; - *out_import_target_path = import_target_str; - - // search relative to importing file - search_dir = buf_alloc(); - os_path_dirname(source_import->data.structure.root_struct->path, search_dir); - - source_kind = SourceKindNonRoot; - } - - buf_resize(out_full_path, 0); - os_path_join(search_dir, *out_import_target_path, out_full_path); - - Buf *import_code = buf_alloc(); - Buf *resolved_path = buf_alloc(); - - Buf *resolve_paths[] = { out_full_path, }; - *resolved_path = os_path_resolve(resolve_paths, 1); - - auto import_entry = g->import_table.maybe_get(resolved_path); - if (import_entry) { - *out_import = import_entry->value; - return ErrorNone; - } - - if (source_kind == SourceKindNonRoot) { - Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { - return ErrorImportOutsidePkgPath; - } - } - - if ((err = file_fetch(g, resolved_path, import_code))) { - return err; - } - - *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); - return ErrorNone; -} - -void AstNode::src() { - RootStruct *root_struct = this->owner->data.structure.root_struct; - uint32_t line = root_struct->token_locs[this->main_token].line + 1; - uint32_t column = root_struct->token_locs[this->main_token].column + 1; - fprintf(stderr, "%s:%" PRIu32 ":%" PRIu32 "\n", - buf_ptr(root_struct->path), - line, column); -} - -void Stage1Air::src() { - Stage1Air *it; - for (it = this; it != nullptr && it->source_node != nullptr; it = it->parent_exec) { - it->source_node->src(); - } -} - -bool is_anon_container(ZigType *ty) { - return ty->id == ZigTypeIdStruct && ( - ty->data.structure.special == StructSpecialInferredTuple || - ty->data.structure.special == StructSpecialInferredStruct); -} - -bool is_opt_err_set(ZigType *ty) { - return ty->id == ZigTypeIdErrorSet || - (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); -} - -// Returns whether the x_optional field of ZigValue is active. -bool type_has_optional_repr(ZigType *ty) { - if (ty->id != ZigTypeIdOptional) { - return false; - } else if (get_src_ptr_type(ty) != nullptr) { - return false; - } else if (is_opt_err_set(ty)) { - return false; - } else { - return true; - } -} - -void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { - uint32_t prev_align = dest->llvm_align; - ConstParent prev_parent = dest->parent; - memcpy(dest, src, sizeof(ZigValue)); - dest->llvm_align = prev_align; - if (src->special != ConstValSpecialStatic) - return; - dest->parent = prev_parent; - if (dest->type->id == ZigTypeIdStruct) { - dest->data.x_struct.fields = alloc_const_vals_ptrs(g, dest->type->data.structure.src_field_count); - for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { - TypeStructField *type_struct_field = dest->type->data.structure.fields[i]; - if (type_struct_field->is_comptime) { - // comptime-known values are stored in the field init_val inside - // the struct type. The data stored here is not supposed to be read - // at all; the code should look at the type system and notice the field - // is comptime and look at the type to learn the value. - continue; - } - copy_const_val(g, dest->data.x_struct.fields[i], src->data.x_struct.fields[i]); - dest->data.x_struct.fields[i]->parent.id = ConstParentIdStruct; - dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; - dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i; - } - } else if (dest->type->id == ZigTypeIdArray) { - switch (dest->data.x_array.special) { - case ConstArraySpecialNone: { - dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate(dest->type->data.array.len); - for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) { - copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]); - dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray; - dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest; - dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i; - } - break; - } - case ConstArraySpecialUndef: { - // Nothing to copy; the above memcpy did everything we needed. - break; - } - case ConstArraySpecialBuf: { - dest->data.x_array.data.s_buf = buf_create_from_buf(src->data.x_array.data.s_buf); - break; - } - } - } else if (dest->type->id == ZigTypeIdUnion) { - bigint_init_bigint(&dest->data.x_union.tag, &src->data.x_union.tag); - dest->data.x_union.payload = g->pass1_arena->create(); - copy_const_val(g, dest->data.x_union.payload, src->data.x_union.payload); - dest->data.x_union.payload->parent.id = ConstParentIdUnion; - dest->data.x_union.payload->parent.data.p_union.union_val = dest; - } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { - dest->data.x_optional = g->pass1_arena->create(); - copy_const_val(g, dest->data.x_optional, src->data.x_optional); - dest->data.x_optional->parent.id = ConstParentIdOptionalPayload; - dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest; - } -} - -bool optional_value_is_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (get_src_ptr_type(val->type) != nullptr) { - if (val->data.x_ptr.special == ConstPtrSpecialNull) { - return true; - } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return val->data.x_ptr.data.hard_coded_addr.addr == 0; - } else { - return false; - } - } else if (is_opt_err_set(val->type)) { - return val->data.x_err_set == nullptr; - } else { - return val->data.x_optional == nullptr; - } -} - -bool type_is_numeric(ZigType *ty) { - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdUndefined: - return true; - - case ZigTypeIdVector: - return type_is_numeric(ty->data.vector.elem_type); - - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - case ZigTypeIdEnumLiteral: - return false; - } - zig_unreachable(); -} - -static void dump_value_indent_error_set(ZigValue *val, int indent) { - fprintf(stderr, "\n"); -} - -static void dump_value_indent(ZigValue *val, int indent); - -static void dump_value_indent_ptr(ZigValue *val, int indent) { - switch (val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - fprintf(stderr, "\n"); - return; - case ConstPtrSpecialNull: - fprintf(stderr, "\n"); - return; - case ConstPtrSpecialRef: - fprintf(stderr, "data.x_ptr.data.ref.pointee, indent + 1); - break; - case ConstPtrSpecialBaseStruct: { - ZigValue *struct_val = val->data.x_ptr.data.base_struct.struct_val; - size_t field_index = val->data.x_ptr.data.base_struct.field_index; - fprintf(stderr, "data.x_struct.fields[field_index]; - if (field_val != nullptr) { - dump_value_indent(field_val, indent + 1); - } else { - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, "(invalid null field)\n"); - } - } - break; - } - case ConstPtrSpecialBaseOptionalPayload: { - ZigValue *optional_val = val->data.x_ptr.data.base_optional_payload.optional_val; - fprintf(stderr, "\n"); -} - -static void dump_value_indent(ZigValue *val, int indent) { - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, "Value@%p(", val); - if (val->type != nullptr) { - fprintf(stderr, "%s)", buf_ptr(&val->type->name)); - } else { - fprintf(stderr, "type=nullptr)"); - } - switch (val->special) { - case ConstValSpecialUndef: - fprintf(stderr, "[undefined]\n"); - return; - case ConstValSpecialLazy: - fprintf(stderr, "[lazy]\n"); - return; - case ConstValSpecialRuntime: - fprintf(stderr, "[runtime]\n"); - return; - case ConstValSpecialStatic: - break; - } - if (val->type == nullptr) - return; - switch (val->type->id) { - case ZigTypeIdInvalid: - fprintf(stderr, "\n"); - return; - case ZigTypeIdUnreachable: - fprintf(stderr, "\n"); - return; - case ZigTypeIdUndefined: - fprintf(stderr, "\n"); - return; - case ZigTypeIdVoid: - fprintf(stderr, "<{}>\n"); - return; - case ZigTypeIdMetaType: - fprintf(stderr, "<%s>\n", buf_ptr(&val->data.x_type->name)); - return; - case ZigTypeIdBool: - fprintf(stderr, "<%s>\n", val->data.x_bool ? "true" : "false"); - return; - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - Buf *tmp_buf = buf_alloc(); - bigint_append_buf(tmp_buf, &val->data.x_bigint, 10); - fprintf(stderr, "<%s>\n", buf_ptr(tmp_buf)); - buf_destroy(tmp_buf); - return; - } - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: - fprintf(stderr, "\n"); - return; - - case ZigTypeIdStruct: - fprintf(stderr, "type->data.structure.src_field_count; i += 1) { - for (int j = 0; j < indent; j += 1) { - fprintf(stderr, " "); - } - TypeStructField *field = val->type->data.structure.fields[i]; - fprintf(stderr, "%s: ", buf_ptr(field->name)); - if (field->is_comptime) { - fprintf(stderr, ""); - } else if (val->data.x_struct.fields == nullptr) { - fprintf(stderr, "\n"); - } else { - dump_value_indent(val->data.x_struct.fields[i], 1); - } - } - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - - case ZigTypeIdOptional: - if (get_src_ptr_type(val->type) != nullptr) { - return dump_value_indent_ptr(val, indent); - } else if (val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { - return dump_value_indent_error_set(val, indent); - } else { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_optional, indent + 1); - - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - } - case ZigTypeIdErrorUnion: - if (val->data.x_err_union.payload != nullptr) { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_err_union.payload, indent + 1); - } else { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_err_union.error_set, 0); - } - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - - case ZigTypeIdPointer: - return dump_value_indent_ptr(val, indent); - - case ZigTypeIdErrorSet: - return dump_value_indent_error_set(val, indent); - - case ZigTypeIdVector: - case ZigTypeIdArray: - case ZigTypeIdNull: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - case ZigTypeIdEnumLiteral: - fprintf(stderr, "\n"); - return; - } - zig_unreachable(); -} - -void ZigValue::dump() { - dump_value_indent(this, 0); -} - -// float ops that take a single argument -//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, lround, llround, lrint, llrint -const char *float_un_op_to_name(BuiltinFnId op) { - switch (op) { - case BuiltinFnIdSqrt: - return "sqrt"; - case BuiltinFnIdSin: - return "sin"; - case BuiltinFnIdCos: - return "cos"; - case BuiltinFnIdTan: - return "tan"; - case BuiltinFnIdExp: - return "exp"; - case BuiltinFnIdExp2: - return "exp2"; - case BuiltinFnIdLog: - return "log"; - case BuiltinFnIdLog10: - return "log10"; - case BuiltinFnIdLog2: - return "log2"; - case BuiltinFnIdFabs: - return "fabs"; - case BuiltinFnIdFloor: - return "floor"; - case BuiltinFnIdCeil: - return "ceil"; - case BuiltinFnIdTrunc: - return "trunc"; - case BuiltinFnIdNearbyInt: - return "nearbyint"; - case BuiltinFnIdRound: - return "round"; - case BuiltinFnIdMulAdd: - return "fma"; - default: - zig_unreachable(); - } -} diff --git a/src/stage1/analyze.hpp b/src/stage1/analyze.hpp deleted file mode 100644 index 64e0e199f877..000000000000 --- a/src/stage1/analyze.hpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ANALYZE_HPP -#define ZIG_ANALYZE_HPP - -#include "all_types.hpp" - -void semantic_analyze(CodeGen *g); -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg); -ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, - uint32_t bad_index); -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); -ZigType *new_type_table_entry(ZigTypeId id); -ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); -ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); -ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, - bool is_const, bool is_volatile, PtrLen ptr_len, - uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero); -ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, - bool is_const, bool is_volatile, PtrLen ptr_len, - uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field, - ZigValue *sentinel); -uint64_t type_size(CodeGen *g, ZigType *type_entry); -uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); -ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); -ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); -ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); -ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); -ZigType *get_optional_type(CodeGen *g, ZigType *child_type); -ZigType *get_optional_type2(CodeGen *g, ZigType *child_type); -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel); -ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type); -ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, - AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout); -ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); -ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type); -ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry); -ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name); -ZigType *get_test_fn_type(CodeGen *g); -ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type); -bool handle_is_ptr(CodeGen *g, ZigType *type_entry); -Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc); -uint32_t get_async_frame_align_bytes(CodeGen *g); - -bool type_has_bits(CodeGen *g, ZigType *type_entry); -Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result); - -bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id); - -enum ExternPosition { - ExternPositionFunctionParameter, - ExternPositionFunctionReturn, - ExternPositionOther, // array element, struct field, optional element, etc -}; - -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result); -bool ptr_allows_addr_zero(ZigType *ptr_type); - -// Deprecated, use `type_is_nonnull_ptr2` -bool type_is_nonnull_ptr(CodeGen *g, ZigType *type); -Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result); - -ZigType *get_codegen_ptr_type_bail(CodeGen *g, ZigType *type); -Error get_codegen_ptr_type(CodeGen *g, ZigType *type, ZigType **result); - -enum SourceKind { - SourceKindRoot, - SourceKindPkgMain, - SourceKindNonRoot, - SourceKindCImport, -}; -ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Buf *source_code, - SourceKind source_kind); - -ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); -Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); -Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name); -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy); -void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope); - -ZigType *get_src_ptr_type(ZigType *type); -uint32_t get_ptr_align(CodeGen *g, ZigType *type); -bool get_ptr_const(CodeGen *g, ZigType *type); -ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry); -ZigType *container_ref_type(ZigType *type_entry); -bool type_is_complete(ZigType *type_entry); -bool type_is_resolved(ZigType *type_entry, ResolveStatus status); -bool type_is_invalid(ZigType *type_entry); -bool type_is_global_error_set(ZigType *err_set_type); -ScopeDecls *get_container_scope(ZigType *type_entry); -TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); -TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); -TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name); -TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag); -TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); - -bool is_ref(ZigType *type_entry); -bool is_array_ref(ZigType *type_entry); -bool is_container_ref(ZigType *type_entry); -Error is_valid_vector_elem_type(CodeGen *g, ZigType *elem_type, bool *result); -void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); -ZigFn *scope_fn_entry(Scope *scope); -ZigPackage *scope_package(Scope *scope); -ZigType *get_scope_import(Scope *scope); -ScopeTypeOf *get_scope_typeof(Scope *scope); -void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); -ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ZigValue *init_value, Tld *src_tld, ZigType *var_type); -ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); -void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type); -ZigFn *create_fn(CodeGen *g, AstNode *proto_node); -void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, CallingConvention cc, size_t param_count_alloc); -AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); -Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); -void complete_enum(CodeGen *g, ZigType *enum_type); -bool ir_get_var_is_comptime(ZigVar *var); -bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b); -void eval_min_max_value(CodeGen *g, ZigType *type_entry, ZigValue *const_val, bool is_max); -void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max); - -void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val); - -ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name); -ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_var_scope(CodeGen *g, AstNode *node, Scope *parent, ZigVar *var); -ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); -Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, Stage1ZirInst *is_comptime); -Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); - -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str); -ZigValue *create_const_str_lit(CodeGen *g, Buf *str); -ZigValue *create_sentineled_str_lit(CodeGen *g, Buf *str, ZigValue *sentinel); - -void init_const_bigint(ZigValue *const_val, ZigType *type, const BigInt *bigint); -ZigValue *create_const_bigint(CodeGen *g, ZigType *type, const BigInt *bigint); - -void init_const_unsigned_negative(ZigValue *const_val, ZigType *type, uint64_t x, bool negative); -ZigValue *create_const_unsigned_negative(CodeGen *g, ZigType *type, uint64_t x, bool negative); - -void init_const_signed(ZigValue *const_val, ZigType *type, int64_t x); -ZigValue *create_const_signed(CodeGen *g, ZigType *type, int64_t x); - -void init_const_usize(CodeGen *g, ZigValue *const_val, uint64_t x); -ZigValue *create_const_usize(CodeGen *g, uint64_t x); - -void init_const_float(ZigValue *const_val, ZigType *type, double value); -ZigValue *create_const_float(CodeGen *g, ZigType *type, double value); - -void init_const_enum(ZigValue *const_val, ZigType *type, const BigInt *tag); -ZigValue *create_const_enum(CodeGen *g, ZigType *type, const BigInt *tag); - -void init_const_bool(CodeGen *g, ZigValue *const_val, bool value); -ZigValue *create_const_bool(CodeGen *g, bool value); - -void init_const_type(CodeGen *g, ZigValue *const_val, ZigType *type_value); -ZigValue *create_const_type(CodeGen *g, ZigType *type_value); - -void init_const_runtime(ZigValue *const_val, ZigType *type); -ZigValue *create_const_runtime(CodeGen *g, ZigType *type); - -void init_const_ptr_ref(CodeGen *g, ZigValue *const_val, ZigValue *pointee_val, bool is_const); -ZigValue *create_const_ptr_ref(CodeGen *g, ZigValue *pointee_val, bool is_const); - -void init_const_ptr_hard_coded_addr(CodeGen *g, ZigValue *const_val, ZigType *pointee_type, - size_t addr, bool is_const); -ZigValue *create_const_ptr_hard_coded_addr(CodeGen *g, ZigType *pointee_type, - size_t addr, bool is_const); - -void init_const_ptr_array(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t elem_index, bool is_const, PtrLen ptr_len); -ZigValue *create_const_ptr_array(CodeGen *g, ZigValue *array_val, size_t elem_index, - bool is_const, PtrLen ptr_len); - -void init_const_slice(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t start, size_t len, bool is_const, ZigValue *sentinel); -ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size_t len, bool is_const, ZigValue *sentinel); - -void init_const_null(ZigValue *const_val, ZigType *type); -ZigValue *create_const_null(CodeGen *g, ZigType *type); - -void init_const_fn(ZigValue *const_val, ZigFn *fn); -ZigValue *create_const_fn(CodeGen *g, ZigFn *fn); - -ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count); -ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count); - -TypeStructField **alloc_type_struct_fields(size_t count); -TypeStructField **realloc_type_struct_fields(TypeStructField **ptr, size_t old_count, size_t new_count); - -ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -void expand_undef_array(CodeGen *g, ZigValue *const_val); -void expand_undef_struct(CodeGen *g, ZigValue *const_val); -void update_compile_var(CodeGen *g, Buf *name, ZigValue *value); - -const char *type_id_name(ZigTypeId id); -ZigTypeId type_id_at_index(size_t index); -size_t type_id_len(); -size_t type_id_index(ZigType *entry); -ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); -bool optional_value_is_null(ZigValue *val); - -uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); -ZigType *get_align_amt_type(CodeGen *g); -ZigPackage *new_anonymous_package(void); - -Buf *const_value_to_buffer(ZigValue *const_val); -void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc); -void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage); - - -ZigValue *get_builtin_value(CodeGen *codegen, const char *name); -ZigType *get_builtin_type(CodeGen *codegen, const char *name); -ZigType *get_stack_trace_type(CodeGen *g); -bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node); - -ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry); - -bool fn_type_can_fail(FnTypeId *fn_type_id); -bool type_can_fail(ZigType *type_entry); -bool fn_eval_cacheable(Scope *scope, ZigType *return_type); -AstNode *type_decl_node(ZigType *type_entry); - -Error get_primitive_type(CodeGen *g, Buf *name, ZigType **result); - -bool calling_convention_allows_zig_types(CallingConvention cc); -const char *calling_convention_name(CallingConvention cc); - -const char *address_space_name(AddressSpace as); - -Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); - -void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); -X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); -bool type_is_c_abi_int_bail(CodeGen *g, ZigType *ty); -Error type_is_c_abi_int(CodeGen *g, ZigType *ty, bool *result); -bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); -const char *container_string(ContainerKind kind); - -uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field); - -enum ReqCompTime { - ReqCompTimeInvalid, - ReqCompTimeNo, - ReqCompTimeYes, -}; -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); - -OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); - -Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *const_val, ZigType *wanted_type); - -void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn); -Buf *type_bare_name(ZigType *t); -Buf *type_h_name(ZigType *t); - -LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type); -LLVMTypeRef get_llvm_c_abi_type(CodeGen *g, ZigType *type); -ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type); - -void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_path, bool translate_c, - FileExt source_kind); - -void src_assert_impl(bool ok, AstNode *source_node, const char *file, unsigned int line); -bool is_container(ZigType *type_entry); -ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, UndefAllowed undef); - -void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); -bool fn_is_async(ZigFn *fn); -CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto); -bool is_valid_return_type(ZigType* type); -bool is_valid_param_type(ZigType* type); - -Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *type_val, uint32_t *abi_align); -Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ZigValue *type_val, - size_t *abi_size, size_t *size_in_bits); -Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type, - ZigValue *parent_type_val, bool *is_zero_bits); -ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); -ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); - -void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); - -Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str, - ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); -ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry); -bool is_anon_container(ZigType *ty); -void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src); -bool type_has_optional_repr(ZigType *ty); -bool is_opt_err_set(ZigType *ty); -bool type_is_numeric(ZigType *ty); -const char *float_un_op_to_name(BuiltinFnId op); - -#define src_assert(OK, SOURCE_NODE) src_assert_impl((OK), (SOURCE_NODE), __FILE__, __LINE__) - -#endif diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp deleted file mode 100644 index 12d1239e82f7..000000000000 --- a/src/stage1/astgen.cpp +++ /dev/null @@ -1,8339 +0,0 @@ -/* - * Copyright (c) 2021 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "astgen.hpp" -#include "analyze.hpp" -#include "util.hpp" -#include "os.hpp" -#include "parser.hpp" - -struct Stage1AstGen { - CodeGen *codegen; - Stage1Zir *exec; - Stage1ZirBasicBlock *current_basic_block; - AstNode *main_block_node; - size_t next_debug_id; - ZigFn *fn; - bool in_c_import_scope; -}; - -static Stage1ZirInst *astgen_node(Stage1AstGen *ag, AstNode *node, Scope *scope); -static Stage1ZirInst *astgen_node_extra(Stage1AstGen *ag, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc); - -static Stage1ZirInst *ir_lval_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *value, LVal lval, - ResultLoc *result_loc); -static Stage1ZirInst *ir_expr_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *inst, - ResultLoc *result_loc); -static Stage1ZirInst *astgen_union_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc); -static ResultLocCast *ir_build_cast_result_loc(Stage1AstGen *ag, Stage1ZirInst *dest_type, - ResultLoc *parent_result_loc); -static ZigVar *ir_create_var(Stage1AstGen *ag, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime); -static void build_decl_var_and_init(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1ZirInst *init, const char *name_hint, Stage1ZirInst *is_comptime); - -static void ir_assert_impl(bool ok, Stage1ZirInst *source_instruction, char const *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -static ErrorMsg *exec_add_error_node(CodeGen *codegen, Stage1Zir *exec, AstNode *source_node, Buf *msg) { - ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - invalidate_exec(exec, err_msg); - return err_msg; -} - - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - - -static bool instr_is_unreachable(Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdCondBr: - case Stage1ZirInstIdReturn: - case Stage1ZirInstIdBr: - case Stage1ZirInstIdUnreachable: - case Stage1ZirInstIdSwitchBr: - case Stage1ZirInstIdPanic: - return true; - default: - return false; - } -} - -void destroy_instruction_src(Stage1ZirInst *inst) { - switch (inst->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdReturn: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBinOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMergeErrSets: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdDeclVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCall: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAsyncCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCondBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPhi: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdContainerInitList: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdContainerInitFields: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnreachable: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdElemPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdVarPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdLoadPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdStorePtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetCold: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetRuntimeSafety: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetFloatMode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdArrayType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSliceType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAnyFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAsm: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSizeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOptionalUnwrapPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPopCount: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdClz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCtz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBswap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitReverse: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchElseVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchTarget: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCompileErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCompileLog: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCInclude: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCDefine: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCUndef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEmbedFile: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCmpxchg: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFence: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdReduce: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTruncate: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrSetCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToFloat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBoolToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdVectorType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdShuffleVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSelect: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSplat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBoolNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMemset: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMemcpy: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBreakpoint: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdReturnAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameHandle: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameSize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlignOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOverflowOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnwrapErrCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnwrapErrPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFnProto: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestComptime: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToEnum: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckStatementIsVoid: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTagName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrTypeSimple: - case Stage1ZirInstIdPtrTypeSimpleConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdDeclRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPanic: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFieldParentPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeInfo: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdHasField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetEvalBranchQuota: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlignCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdImplicitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResolveResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResetResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetAlignStack: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdArgTypeAllowVarFalse: - case Stage1ZirInstIdArgTypeAllowVarTrue: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdExport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdExtern: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrorReturnTrace: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrorUnion: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicRmw: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSaveErrRetAddr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAddImplicitReturnType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMulAdd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicLoad: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicStore: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEnumToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckRuntimeScope: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdHasDecl: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUndeclaredIdent: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlloca: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEndExpr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnionInitNamedField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSuspendBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSuspendFinish: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResume: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAwait: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSpillBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSpillEnd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCallArgs: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdWasmMemorySize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdWasmMemoryGrow: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSrc: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPrefetch: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAddrSpaceCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - } - zig_unreachable(); -} - - -bool ir_should_inline(Stage1Zir *exec, Scope *scope) { - if (exec->is_inline) - return true; - - while (scope != nullptr) { - if (scope->id == ScopeIdCompTime) - return true; - if (scope->id == ScopeIdTypeOf) - return false; - if (scope->id == ScopeIdFnDef) - break; - scope = scope->parent; - } - return false; -} - -static void ir_instruction_append(Stage1ZirBasicBlock *basic_block, Stage1ZirInst *instruction) { - assert(basic_block); - assert(instruction); - basic_block->instruction_list.append(instruction); -} - -static size_t irb_next_debug_id(Stage1AstGen *ag) { - size_t result = ag->next_debug_id; - ag->next_debug_id += 1; - return result; -} - -static void ir_ref_bb(Stage1ZirBasicBlock *bb) { - bb->ref_count += 1; -} - -static void ir_ref_instruction(Stage1ZirInst *instruction, Stage1ZirBasicBlock *cur_bb) { - assert(instruction->id != Stage1ZirInstIdInvalid); - instruction->ref_count += 1; - if (instruction->owner_bb != cur_bb && !instr_is_unreachable(instruction) - && instruction->id != Stage1ZirInstIdConst) - { - ir_ref_bb(instruction->owner_bb); - } -} - -static Stage1ZirBasicBlock *ir_create_basic_block(Stage1AstGen *ag, Scope *scope, const char *name_hint) { - Stage1ZirBasicBlock *result = heap::c_allocator.create(); - result->scope = scope; - result->name_hint = name_hint; - result->debug_id = irb_next_debug_id(ag); - result->index = UINT32_MAX; // set later - return result; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstDeclVar *) { - return Stage1ZirInstIdDeclVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBr *) { - return Stage1ZirInstIdBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCondBr *) { - return Stage1ZirInstIdCondBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchBr *) { - return Stage1ZirInstIdSwitchBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchVar *) { - return Stage1ZirInstIdSwitchVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchElseVar *) { - return Stage1ZirInstIdSwitchElseVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchTarget *) { - return Stage1ZirInstIdSwitchTarget; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPhi *) { - return Stage1ZirInstIdPhi; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnOp *) { - return Stage1ZirInstIdUnOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBinOp *) { - return Stage1ZirInstIdBinOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMergeErrSets *) { - return Stage1ZirInstIdMergeErrSets; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstLoadPtr *) { - return Stage1ZirInstIdLoadPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstStorePtr *) { - return Stage1ZirInstIdStorePtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFieldPtr *) { - return Stage1ZirInstIdFieldPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstElemPtr *) { - return Stage1ZirInstIdElemPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstVarPtr *) { - return Stage1ZirInstIdVarPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCall *) { - return Stage1ZirInstIdCall; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCallArgs *) { - return Stage1ZirInstIdCallArgs; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCallExtra *) { - return Stage1ZirInstIdCallExtra; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAsyncCallExtra *) { - return Stage1ZirInstIdAsyncCallExtra; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstConst *) { - return Stage1ZirInstIdConst; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReturn *) { - return Stage1ZirInstIdReturn; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstContainerInitList *) { - return Stage1ZirInstIdContainerInitList; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstContainerInitFields *) { - return Stage1ZirInstIdContainerInitFields; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnreachable *) { - return Stage1ZirInstIdUnreachable; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeOf *) { - return Stage1ZirInstIdTypeOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetCold *) { - return Stage1ZirInstIdSetCold; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetRuntimeSafety *) { - return Stage1ZirInstIdSetRuntimeSafety; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetFloatMode *) { - return Stage1ZirInstIdSetFloatMode; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstArrayType *) { - return Stage1ZirInstIdArrayType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAnyFrameType *) { - return Stage1ZirInstIdAnyFrameType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSliceType *) { - return Stage1ZirInstIdSliceType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAsm *) { - return Stage1ZirInstIdAsm; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSizeOf *) { - return Stage1ZirInstIdSizeOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestNonNull *) { - return Stage1ZirInstIdTestNonNull; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOptionalUnwrapPtr *) { - return Stage1ZirInstIdOptionalUnwrapPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstClz *) { - return Stage1ZirInstIdClz; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCtz *) { - return Stage1ZirInstIdCtz; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPopCount *) { - return Stage1ZirInstIdPopCount; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBswap *) { - return Stage1ZirInstIdBswap; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitReverse *) { - return Stage1ZirInstIdBitReverse; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstImport *) { - return Stage1ZirInstIdImport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCImport *) { - return Stage1ZirInstIdCImport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCInclude *) { - return Stage1ZirInstIdCInclude; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCDefine *) { - return Stage1ZirInstIdCDefine; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCUndef *) { - return Stage1ZirInstIdCUndef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstRef *) { - return Stage1ZirInstIdRef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCompileErr *) { - return Stage1ZirInstIdCompileErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCompileLog *) { - return Stage1ZirInstIdCompileLog; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrName *) { - return Stage1ZirInstIdErrName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEmbedFile *) { - return Stage1ZirInstIdEmbedFile; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCmpxchg *) { - return Stage1ZirInstIdCmpxchg; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFence *) { - return Stage1ZirInstIdFence; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReduce *) { - return Stage1ZirInstIdReduce; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTruncate *) { - return Stage1ZirInstIdTruncate; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntCast *) { - return Stage1ZirInstIdIntCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatCast *) { - return Stage1ZirInstIdFloatCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToFloat *) { - return Stage1ZirInstIdIntToFloat; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatToInt *) { - return Stage1ZirInstIdFloatToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBoolToInt *) { - return Stage1ZirInstIdBoolToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstVectorType *) { - return Stage1ZirInstIdVectorType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstShuffleVector *) { - return Stage1ZirInstIdShuffleVector; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSelect *) { - return Stage1ZirInstIdSelect; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSplat *) { - return Stage1ZirInstIdSplat; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBoolNot *) { - return Stage1ZirInstIdBoolNot; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMemset *) { - return Stage1ZirInstIdMemset; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMemcpy *) { - return Stage1ZirInstIdMemcpy; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSlice *) { - return Stage1ZirInstIdSlice; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBreakpoint *) { - return Stage1ZirInstIdBreakpoint; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReturnAddress *) { - return Stage1ZirInstIdReturnAddress; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameAddress *) { - return Stage1ZirInstIdFrameAddress; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameHandle *) { - return Stage1ZirInstIdFrameHandle; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameType *) { - return Stage1ZirInstIdFrameType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameSize *) { - return Stage1ZirInstIdFrameSize; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlignOf *) { - return Stage1ZirInstIdAlignOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOverflowOp *) { - return Stage1ZirInstIdOverflowOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestErr *) { - return Stage1ZirInstIdTestErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMulAdd *) { - return Stage1ZirInstIdMulAdd; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatOp *) { - return Stage1ZirInstIdFloatOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnwrapErrCode *) { - return Stage1ZirInstIdUnwrapErrCode; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnwrapErrPayload *) { - return Stage1ZirInstIdUnwrapErrPayload; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFnProto *) { - return Stage1ZirInstIdFnProto; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestComptime *) { - return Stage1ZirInstIdTestComptime; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrCast *) { - return Stage1ZirInstIdPtrCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitCast *) { - return Stage1ZirInstIdBitCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToPtr *) { - return Stage1ZirInstIdIntToPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrToInt *) { - return Stage1ZirInstIdPtrToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToEnum *) { - return Stage1ZirInstIdIntToEnum; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEnumToInt *) { - return Stage1ZirInstIdEnumToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToErr *) { - return Stage1ZirInstIdIntToErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrToInt *) { - return Stage1ZirInstIdErrToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCheckStatementIsVoid *) { - return Stage1ZirInstIdCheckStatementIsVoid; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeName *) { - return Stage1ZirInstIdTypeName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstDeclRef *) { - return Stage1ZirInstIdDeclRef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPanic *) { - return Stage1ZirInstIdPanic; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTagName *) { - return Stage1ZirInstIdTagName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFieldParentPtr *) { - return Stage1ZirInstIdFieldParentPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOffsetOf *) { - return Stage1ZirInstIdOffsetOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitOffsetOf *) { - return Stage1ZirInstIdBitOffsetOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeInfo *) { - return Stage1ZirInstIdTypeInfo; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstType *) { - return Stage1ZirInstIdType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstHasField *) { - return Stage1ZirInstIdHasField; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetEvalBranchQuota *) { - return Stage1ZirInstIdSetEvalBranchQuota; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrType *) { - return Stage1ZirInstIdPtrType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlignCast *) { - return Stage1ZirInstIdAlignCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstImplicitCast *) { - return Stage1ZirInstIdImplicitCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResolveResult *) { - return Stage1ZirInstIdResolveResult; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResetResult *) { - return Stage1ZirInstIdResetResult; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetAlignStack *) { - return Stage1ZirInstIdSetAlignStack; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstExport *) { - return Stage1ZirInstIdExport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstExtern *) { - return Stage1ZirInstIdExtern; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrorReturnTrace *) { - return Stage1ZirInstIdErrorReturnTrace; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrorUnion *) { - return Stage1ZirInstIdErrorUnion; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicRmw *) { - return Stage1ZirInstIdAtomicRmw; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicLoad *) { - return Stage1ZirInstIdAtomicLoad; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicStore *) { - return Stage1ZirInstIdAtomicStore; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSaveErrRetAddr *) { - return Stage1ZirInstIdSaveErrRetAddr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddImplicitReturnType *) { - return Stage1ZirInstIdAddImplicitReturnType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrSetCast *) { - return Stage1ZirInstIdErrSetCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCheckRuntimeScope *) { - return Stage1ZirInstIdCheckRuntimeScope; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstHasDecl *) { - return Stage1ZirInstIdHasDecl; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUndeclaredIdent *) { - return Stage1ZirInstIdUndeclaredIdent; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlloca *) { - return Stage1ZirInstIdAlloca; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEndExpr *) { - return Stage1ZirInstIdEndExpr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnionInitNamedField *) { - return Stage1ZirInstIdUnionInitNamedField; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSuspendBegin *) { - return Stage1ZirInstIdSuspendBegin; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSuspendFinish *) { - return Stage1ZirInstIdSuspendFinish; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAwait *) { - return Stage1ZirInstIdAwait; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResume *) { - return Stage1ZirInstIdResume; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSpillBegin *) { - return Stage1ZirInstIdSpillBegin; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSpillEnd *) { - return Stage1ZirInstIdSpillEnd; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstWasmMemorySize *) { - return Stage1ZirInstIdWasmMemorySize; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstWasmMemoryGrow *) { - return Stage1ZirInstIdWasmMemoryGrow; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) { - return Stage1ZirInstIdSrc; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) { - return Stage1ZirInstIdPrefetch; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddrSpaceCast *) { - return Stage1ZirInstIdAddrSpaceCast; -} - -template -static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = irb_next_debug_id(ag); - special_instruction->base.owner_bb = ag->current_basic_block; - return special_instruction; -} - -template -static T *ir_build_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &special_instruction->base); - return special_instruction; -} - -static Stage1ZirInst *ir_build_cond_br(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *condition, - Stage1ZirBasicBlock *then_block, Stage1ZirBasicBlock *else_block, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstCondBr *inst = ir_build_instruction(ag, scope, source_node); - inst->condition = condition; - inst->then_block = then_block; - inst->else_block = else_block; - inst->is_comptime = is_comptime; - - ir_ref_instruction(condition, ag->current_basic_block); - ir_ref_bb(then_block); - ir_ref_bb(else_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_return_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *operand) { - Stage1ZirInstReturn *inst = ir_build_instruction(ag, scope, source_node); - inst->operand = operand; - - if (operand != nullptr) ir_ref_instruction(operand, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_const_void(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_void(); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_undefined(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_undefined(); - const_instruction->value->special = ConstValSpecialUndef; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_uint(Stage1AstGen *ag, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bigint(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - BigInt bigint) -{ - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bigint = bigint; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bigfloat(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - BigFloat bigfloat) -{ - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_float; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bigfloat = bigfloat; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_null(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_null(); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_usize(Stage1AstGen *ag, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_usize; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_create_const_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = type_entry; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - Stage1ZirInst *instruction = ir_create_const_type(ag, scope, source_node, type_entry); - ir_instruction_append(ag->current_basic_block, instruction); - return instruction; -} - -static Stage1ZirInst *ir_build_const_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigType *import) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = import; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bool(Stage1AstGen *ag, Scope *scope, AstNode *source_node, bool value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_bool; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bool = value; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_enum_literal(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *name) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_enum_literal; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_enum_literal = name; - return &const_instruction->base; -} - -// Consumes `str`. -static Stage1ZirInst *ir_create_const_str_lit(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *str) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - init_const_str_lit(ag->codegen, const_instruction->value, str, true); - - return &const_instruction->base; -} - -// Consumes `str`. -static Stage1ZirInst *ir_build_const_str_lit(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *str) { - Stage1ZirInst *instruction = ir_create_const_str_lit(ag, scope, source_node, str); - ir_instruction_append(ag->current_basic_block, instruction); - return instruction; -} - -static Stage1ZirInst *ir_build_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrBinOp op_id, - Stage1ZirInst *op1, Stage1ZirInst *op2, bool safety_check_on) -{ - Stage1ZirInstBinOp *inst = ir_build_instruction(ag, scope, source_node); - inst->op_id = op_id; - inst->op1 = op1; - inst->op2 = op2; - inst->safety_check_on = safety_check_on; - - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_merge_err_sets(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *op1, Stage1ZirInst *op2, Buf *type_name) -{ - Stage1ZirInstMergeErrSets *inst = ir_build_instruction(ag, scope, source_node); - inst->op1 = op1; - inst->op2 = op2; - inst->type_name = type_name; - - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_var_ptr_x(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var, - ScopeFnDef *crossed_fndef_scope) -{ - Stage1ZirInstVarPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->var = var; - instruction->crossed_fndef_scope = crossed_fndef_scope; - - var->ref_count += 1; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_var_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var) { - return ir_build_var_ptr_x(ag, scope, source_node, var, nullptr); -} - -static Stage1ZirInst *ir_build_elem_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *array_ptr, Stage1ZirInst *elem_index, bool safety_check_on, PtrLen ptr_len, - AstNode *init_array_type_source_node) -{ - Stage1ZirInstElemPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->array_ptr = array_ptr; - instruction->elem_index = elem_index; - instruction->safety_check_on = safety_check_on; - instruction->ptr_len = ptr_len; - instruction->init_array_type_source_node = init_array_type_source_node; - - ir_ref_instruction(array_ptr, ag->current_basic_block); - ir_ref_instruction(elem_index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_ptr_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_ptr, Stage1ZirInst *field_name_expr, bool initializing) -{ - Stage1ZirInstFieldPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = nullptr; - instruction->field_name_expr = field_name_expr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, ag->current_basic_block); - ir_ref_instruction(field_name_expr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_ptr, Buf *field_name, bool initializing) -{ - Stage1ZirInstFieldPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = field_name; - instruction->field_name_expr = nullptr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_has_field(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_type, Stage1ZirInst *field_name) -{ - Stage1ZirInstHasField *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_type = container_type; - instruction->field_name = field_name; - - ir_ref_instruction(container_type, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_call_extra(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *options, Stage1ZirInst *fn_ref, Stage1ZirInst *args, ResultLoc *result_loc) -{ - Stage1ZirInstCallExtra *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, ag->current_basic_block); - ir_ref_instruction(fn_ref, ag->current_basic_block); - ir_ref_instruction(args, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_async_call_extra(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - CallModifier modifier, Stage1ZirInst *fn_ref, Stage1ZirInst *ret_ptr, Stage1ZirInst *new_stack, Stage1ZirInst *args, ResultLoc *result_loc) -{ - Stage1ZirInstAsyncCallExtra *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->modifier = modifier; - call_instruction->fn_ref = fn_ref; - call_instruction->ret_ptr = ret_ptr; - call_instruction->new_stack = new_stack; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(fn_ref, ag->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, ag->current_basic_block); - ir_ref_instruction(new_stack, ag->current_basic_block); - ir_ref_instruction(args, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_call_args(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *options, Stage1ZirInst *fn_ref, Stage1ZirInst **args_ptr, size_t args_len, - ResultLoc *result_loc) -{ - Stage1ZirInstCallArgs *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args_ptr = args_ptr; - call_instruction->args_len = args_len; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, ag->current_basic_block); - ir_ref_instruction(fn_ref, ag->current_basic_block); - for (size_t i = 0; i < args_len; i += 1) - ir_ref_instruction(args_ptr[i], ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_call_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1ZirInst *fn_ref, size_t arg_count, Stage1ZirInst **args, - Stage1ZirInst *ret_ptr, CallModifier modifier, bool is_async_call_builtin, - Stage1ZirInst *new_stack, ResultLoc *result_loc) -{ - Stage1ZirInstCall *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->fn_entry = fn_entry; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->arg_count = arg_count; - call_instruction->modifier = modifier; - call_instruction->is_async_call_builtin = is_async_call_builtin; - call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; - call_instruction->ret_ptr = ret_ptr; - - if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ag->current_basic_block); - for (size_t i = 0; i < arg_count; i += 1) - ir_ref_instruction(args[i], ag->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, ag->current_basic_block); - if (new_stack != nullptr) ir_ref_instruction(new_stack, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *source_node, bool merge_comptime, - size_t incoming_count, Stage1ZirBasicBlock **incoming_blocks, Stage1ZirInst **incoming_values, - ResultLocPeerParent *peer_parent) -{ - assert(incoming_count != 0); - assert(incoming_count != SIZE_MAX); - - Stage1ZirInstPhi *phi_instruction = ir_build_instruction(ag, scope, source_node); - phi_instruction->incoming_count = incoming_count; - phi_instruction->incoming_blocks = incoming_blocks; - phi_instruction->incoming_values = incoming_values; - phi_instruction->peer_parent = peer_parent; - phi_instruction->merge_comptime = merge_comptime; - - for (size_t i = 0; i < incoming_count; i += 1) { - ir_ref_bb(incoming_blocks[i]); - ir_ref_instruction(incoming_values[i], ag->current_basic_block); - } - - return &phi_instruction->base; -} - -static Stage1ZirInst *ir_build_br(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirBasicBlock *dest_block, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstBr *inst = ir_build_instruction(ag, scope, source_node); - inst->dest_block = dest_block; - inst->is_comptime = is_comptime; - - ir_ref_bb(dest_block); - if (is_comptime) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_ptr_type_simple(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const) -{ - Stage1ZirInstPtrTypeSimple *inst = heap::c_allocator.create(); - inst->base.id = is_const ? Stage1ZirInstIdPtrTypeSimpleConst : Stage1ZirInstIdPtrTypeSimple; - inst->base.scope = scope; - inst->base.source_node = source_node; - inst->base.debug_id = irb_next_debug_id(ag); - inst->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &inst->base); - - inst->child_type = child_type; - - ir_ref_instruction(child_type, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_ptr_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, - Stage1ZirInst *sentinel, Stage1ZirInst *align_value, - uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) -{ - if (!is_volatile && ptr_len == PtrLenSingle && sentinel == nullptr && align_value == nullptr && - bit_offset_start == 0 && host_int_bytes == 0 && is_allow_zero == 0) - { - return ir_build_ptr_type_simple(ag, scope, source_node, child_type, is_const); - } - - Stage1ZirInstPtrType *inst = ir_build_instruction(ag, scope, source_node); - inst->sentinel = sentinel; - inst->align_value = align_value; - inst->child_type = child_type; - inst->is_const = is_const; - inst->is_volatile = is_volatile; - inst->ptr_len = ptr_len; - inst->bit_offset_start = bit_offset_start; - inst->host_int_bytes = host_int_bytes; - inst->is_allow_zero = is_allow_zero; - - if (sentinel) ir_ref_instruction(sentinel, ag->current_basic_block); - if (align_value) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_un_op_lval(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrUnOp op_id, - Stage1ZirInst *value, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInstUnOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op_id = op_id; - instruction->value = value; - instruction->lval = lval; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_un_op(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrUnOp op_id, - Stage1ZirInst *value) -{ - return ir_build_un_op_lval(ag, scope, source_node, op_id, value, LValNone, nullptr); -} - -static Stage1ZirInst *ir_build_container_init_list(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t item_count, Stage1ZirInst **elem_result_loc_list, Stage1ZirInst *result_loc, - AstNode *init_array_type_source_node) -{ - Stage1ZirInstContainerInitList *container_init_list_instruction = - ir_build_instruction(ag, scope, source_node); - container_init_list_instruction->item_count = item_count; - container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; - container_init_list_instruction->result_loc = result_loc; - container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; - - for (size_t i = 0; i < item_count; i += 1) { - ir_ref_instruction(elem_result_loc_list[i], ag->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &container_init_list_instruction->base; -} - -static Stage1ZirInst *ir_build_container_init_fields(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t field_count, Stage1ZirInstContainerInitFieldsField *fields, Stage1ZirInst *result_loc) -{ - Stage1ZirInstContainerInitFields *container_init_fields_instruction = - ir_build_instruction(ag, scope, source_node); - container_init_fields_instruction->field_count = field_count; - container_init_fields_instruction->fields = fields; - container_init_fields_instruction->result_loc = result_loc; - - for (size_t i = 0; i < field_count; i += 1) { - ir_ref_instruction(fields[i].result_loc, ag->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &container_init_fields_instruction->base; -} - -static Stage1ZirInst *ir_build_unreachable(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstUnreachable *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInstStorePtr *ir_build_store_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *value) -{ - Stage1ZirInstStorePtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_var_decl_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1ZirInst *align_value, Stage1ZirInst *ptr) -{ - Stage1ZirInstDeclVar *inst = ir_build_instruction(ag, scope, source_node); - inst->var = var; - inst->align_value = align_value; - inst->ptr = ptr; - - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_export(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target, Stage1ZirInst *options) -{ - Stage1ZirInstExport *export_instruction = ir_build_instruction( - ag, scope, source_node); - export_instruction->target = target; - export_instruction->options = options; - - ir_ref_instruction(target, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &export_instruction->base; -} - -static Stage1ZirInst *ir_build_extern(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type, Stage1ZirInst *options) -{ - Stage1ZirInstExtern *extern_instruction = ir_build_instruction( - ag, scope, source_node); - extern_instruction->type = type; - extern_instruction->options = options; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &extern_instruction->base; -} - -static Stage1ZirInst *ir_build_load_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *ptr) { - Stage1ZirInstLoadPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_typeof_n(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst **values, size_t value_count) -{ - assert(value_count >= 2); - - Stage1ZirInstTypeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value.list = values; - instruction->value_count = value_count; - - for (size_t i = 0; i < value_count; i++) - ir_ref_instruction(values[i], ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_typeof_1(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstTypeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value.scalar = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_cold(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *is_cold) { - Stage1ZirInstSetCold *instruction = ir_build_instruction(ag, scope, source_node); - instruction->is_cold = is_cold; - - ir_ref_instruction(is_cold, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_runtime_safety(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *safety_on) -{ - Stage1ZirInstSetRuntimeSafety *inst = ir_build_instruction(ag, scope, source_node); - inst->safety_on = safety_on; - - ir_ref_instruction(safety_on, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_set_float_mode(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *mode_value) -{ - Stage1ZirInstSetFloatMode *instruction = ir_build_instruction(ag, scope, source_node); - instruction->mode_value = mode_value; - - ir_ref_instruction(mode_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_array_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *size, - Stage1ZirInst *sentinel, Stage1ZirInst *child_type) -{ - Stage1ZirInstArrayType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->size = size; - instruction->sentinel = sentinel; - instruction->child_type = child_type; - - ir_ref_instruction(size, ag->current_basic_block); - if (sentinel != nullptr) ir_ref_instruction(sentinel, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_anyframe_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *payload_type) -{ - Stage1ZirInstAnyFrameType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->payload_type = payload_type; - - if (payload_type != nullptr) ir_ref_instruction(payload_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_slice_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const, bool is_volatile, - Stage1ZirInst *sentinel, Stage1ZirInst *align_value, bool is_allow_zero) -{ - Stage1ZirInstSliceType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->is_const = is_const; - instruction->is_volatile = is_volatile; - instruction->child_type = child_type; - instruction->sentinel = sentinel; - instruction->align_value = align_value; - instruction->is_allow_zero = is_allow_zero; - - if (sentinel != nullptr) ir_ref_instruction(sentinel, ag->current_basic_block); - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_asm_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *asm_template, Stage1ZirInst **input_list, Stage1ZirInst **output_types, - ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global) -{ - Stage1ZirInstAsm *instruction = ir_build_instruction(ag, scope, source_node); - instruction->asm_template = asm_template; - instruction->input_list = input_list; - instruction->output_types = output_types; - instruction->output_vars = output_vars; - instruction->return_count = return_count; - instruction->has_side_effects = has_side_effects; - instruction->is_global = is_global; - - assert(source_node->type == NodeTypeAsmExpr); - for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { - Stage1ZirInst *output_type = output_types[i]; - if (output_type) ir_ref_instruction(output_type, ag->current_basic_block); - } - - for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { - Stage1ZirInst *input_value = input_list[i]; - ir_ref_instruction(input_value, ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_size_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value, - bool bit_size) -{ - Stage1ZirInstSizeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->bit_size = bit_size; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_non_null_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value) -{ - Stage1ZirInstTestNonNull *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_optional_unwrap_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *base_ptr, bool safety_check_on) -{ - Stage1ZirInstOptionalUnwrapPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(base_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_clz(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstClz *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ctz(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstCtz *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_pop_count(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstPopCount *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bswap(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstBswap *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_reverse(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstBitReverse *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSwitchBr *ir_build_switch_br_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value, Stage1ZirBasicBlock *else_block, size_t case_count, Stage1ZirInstSwitchBrCase *cases, - Stage1ZirInst *is_comptime, Stage1ZirInst *switch_prongs_void) -{ - Stage1ZirInstSwitchBr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value = target_value; - instruction->else_block = else_block; - instruction->case_count = case_count; - instruction->cases = cases; - instruction->is_comptime = is_comptime; - instruction->switch_prongs_void = switch_prongs_void; - - ir_ref_instruction(target_value, ag->current_basic_block); - ir_ref_instruction(is_comptime, ag->current_basic_block); - ir_ref_bb(else_block); - ir_ref_instruction(switch_prongs_void, ag->current_basic_block); - - for (size_t i = 0; i < case_count; i += 1) { - ir_ref_instruction(cases[i].value, ag->current_basic_block); - ir_ref_bb(cases[i].block); - } - - return instruction; -} - -static Stage1ZirInst *ir_build_switch_target(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr) -{ - Stage1ZirInstSwitchTarget *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_switch_var(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr, Stage1ZirInst **prongs_ptr, size_t prongs_len) -{ - Stage1ZirInstSwitchVar *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - instruction->prongs_ptr = prongs_ptr; - instruction->prongs_len = prongs_len; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - for (size_t i = 0; i < prongs_len; i += 1) { - ir_ref_instruction(prongs_ptr[i], ag->current_basic_block); - } - - return &instruction->base; -} - -// For this instruction the switch_br must be set later. -static Stage1ZirInstSwitchElseVar *ir_build_switch_else_var(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr) -{ - Stage1ZirInstSwitchElseVar *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstImport *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ref_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstRef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_compile_err(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *msg) { - Stage1ZirInstCompileErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg = msg; - - ir_ref_instruction(msg, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_compile_log(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t msg_count, Stage1ZirInst **msg_list) -{ - Stage1ZirInstCompileLog *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg_count = msg_count; - instruction->msg_list = msg_list; - - for (size_t i = 0; i < msg_count; i += 1) { - ir_ref_instruction(msg_list[i], ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_name(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstErrName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstCImport *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_include(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstCInclude *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_define(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name, Stage1ZirInst *value) { - Stage1ZirInstCDefine *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - instruction->value = value; - - ir_ref_instruction(name, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_undef(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstCUndef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_embed_file(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstEmbedFile *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_cmpxchg_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *ptr, Stage1ZirInst *cmp_value, Stage1ZirInst *new_value, - Stage1ZirInst *success_order_value, Stage1ZirInst *failure_order_value, bool is_weak, ResultLoc *result_loc) -{ - Stage1ZirInstCmpxchg *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->ptr = ptr; - instruction->cmp_value = cmp_value; - instruction->new_value = new_value; - instruction->success_order_value = success_order_value; - instruction->failure_order_value = failure_order_value; - instruction->is_weak = is_weak; - instruction->result_loc = result_loc; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(cmp_value, ag->current_basic_block); - ir_ref_instruction(new_value, ag->current_basic_block); - ir_ref_instruction(success_order_value, ag->current_basic_block); - ir_ref_instruction(failure_order_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_fence(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *order) { - Stage1ZirInstFence *instruction = ir_build_instruction(ag, scope, source_node); - instruction->order = order; - - ir_ref_instruction(order, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_reduce(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *op, Stage1ZirInst *value) { - Stage1ZirInstReduce *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op = op; - instruction->value = value; - - ir_ref_instruction(op, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_truncate(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstTruncate *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *dest_type, - Stage1ZirInst *target) -{ - Stage1ZirInstIntCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *dest_type, - Stage1ZirInst *target) -{ - Stage1ZirInstFloatCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_set_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstErrSetCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_float(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToFloat *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstFloatToInt *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bool_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *target) { - Stage1ZirInstBoolToInt *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_vector_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *len, - Stage1ZirInst *elem_type) -{ - Stage1ZirInstVectorType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->len = len; - instruction->elem_type = elem_type; - - ir_ref_instruction(len, ag->current_basic_block); - ir_ref_instruction(elem_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_shuffle_vector(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *scalar_type, Stage1ZirInst *a, Stage1ZirInst *b, Stage1ZirInst *mask) -{ - Stage1ZirInstShuffleVector *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scalar_type = scalar_type; - instruction->a = a; - instruction->b = b; - instruction->mask = mask; - - if (scalar_type != nullptr) ir_ref_instruction(scalar_type, ag->current_basic_block); - ir_ref_instruction(a, ag->current_basic_block); - ir_ref_instruction(b, ag->current_basic_block); - ir_ref_instruction(mask, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_select(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *scalar_type, Stage1ZirInst *pred, Stage1ZirInst *a, Stage1ZirInst *b) -{ - Stage1ZirInstSelect *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scalar_type = scalar_type; - instruction->pred = pred; - instruction->a = a; - instruction->b = b; - - ir_ref_instruction(pred, ag->current_basic_block); - ir_ref_instruction(a, ag->current_basic_block); - ir_ref_instruction(b, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_splat_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *len, Stage1ZirInst *scalar) -{ - Stage1ZirInstSplat *instruction = ir_build_instruction(ag, scope, source_node); - instruction->len = len; - instruction->scalar = scalar; - - ir_ref_instruction(len, ag->current_basic_block); - ir_ref_instruction(scalar, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bool_not(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstBoolNot *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_memset_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_ptr, Stage1ZirInst *byte, Stage1ZirInst *count) -{ - Stage1ZirInstMemset *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->byte = byte; - instruction->count = count; - - ir_ref_instruction(dest_ptr, ag->current_basic_block); - ir_ref_instruction(byte, ag->current_basic_block); - ir_ref_instruction(count, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_memcpy_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_ptr, Stage1ZirInst *src_ptr, Stage1ZirInst *count) -{ - Stage1ZirInstMemcpy *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->src_ptr = src_ptr; - instruction->count = count; - - ir_ref_instruction(dest_ptr, ag->current_basic_block); - ir_ref_instruction(src_ptr, ag->current_basic_block); - ir_ref_instruction(count, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_slice_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *start, Stage1ZirInst *end, Stage1ZirInst *sentinel, - bool safety_check_on, ResultLoc *result_loc) -{ - Stage1ZirInstSlice *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - instruction->start = start; - instruction->end = end; - instruction->sentinel = sentinel; - instruction->safety_check_on = safety_check_on; - instruction->result_loc = result_loc; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(start, ag->current_basic_block); - if (end) ir_ref_instruction(end, ag->current_basic_block); - if (sentinel) ir_ref_instruction(sentinel, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_breakpoint(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstBreakpoint *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_return_address_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstReturnAddress *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_frame_address_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstFrameAddress *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_handle_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstFrameHandle *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_frame_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *fn) { - Stage1ZirInstFrameType *inst = ir_build_instruction(ag, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_frame_size_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *fn) { - Stage1ZirInstFrameSize *inst = ir_build_instruction(ag, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_overflow_op_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - IrOverflowOp op, Stage1ZirInst *type_value, Stage1ZirInst *op1, Stage1ZirInst *op2, Stage1ZirInst *result_ptr) -{ - Stage1ZirInstOverflowOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op = op; - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->result_ptr = result_ptr; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - ir_ref_instruction(result_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_op_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *operand, - BuiltinFnId fn_id) -{ - Stage1ZirInstFloatOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->fn_id = fn_id; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_mul_add_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *op1, Stage1ZirInst *op2, Stage1ZirInst *op3) -{ - Stage1ZirInstMulAdd *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->op3 = op3; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - ir_ref_instruction(op3, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_align_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value) { - Stage1ZirInstAlignOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_err_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *base_ptr, bool resolve_err_set, bool base_ptr_is_payload) -{ - Stage1ZirInstTestErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->resolve_err_set = resolve_err_set; - instruction->base_ptr_is_payload = base_ptr_is_payload; - - ir_ref_instruction(base_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_unwrap_err_code_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *err_union_ptr) -{ - Stage1ZirInstUnwrapErrCode *inst = ir_build_instruction(ag, scope, source_node); - inst->err_union_ptr = err_union_ptr; - - ir_ref_instruction(err_union_ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_unwrap_err_payload_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, bool safety_check_on, bool initializing) -{ - Stage1ZirInstUnwrapErrPayload *inst = ir_build_instruction(ag, scope, source_node); - inst->value = value; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_instruction(value, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_fn_proto(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst **param_types, Stage1ZirInst *align_value, Stage1ZirInst *callconv_value, - Stage1ZirInst *return_type, bool is_var_args) -{ - Stage1ZirInstFnProto *instruction = ir_build_instruction(ag, scope, source_node); - instruction->param_types = param_types; - instruction->align_value = align_value; - instruction->callconv_value = callconv_value; - instruction->return_type = return_type; - instruction->is_var_args = is_var_args; - - assert(source_node->type == NodeTypeFnProto); - size_t param_count = source_node->data.fn_proto.params.length; - if (is_var_args) param_count -= 1; - for (size_t i = 0; i < param_count; i += 1) { - if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], ag->current_basic_block); - } - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - if (callconv_value != nullptr) ir_ref_instruction(callconv_value, ag->current_basic_block); - ir_ref_instruction(return_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_comptime(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstTestComptime *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ptr_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *ptr, bool safety_check_on) -{ - Stage1ZirInstPtrCast *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->ptr = ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_implicit_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, ResultLocCast *result_loc_cast) -{ - Stage1ZirInstImplicitCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->result_loc_cast = result_loc_cast; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, ResultLocBitCast *result_loc_bit_cast) -{ - Stage1ZirInstBitCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->result_loc_bit_cast = result_loc_bit_cast; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_ptr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ptr_to_int_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstPtrToInt *inst = ir_build_instruction(ag, scope, source_node); - inst->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_int_to_enum_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToEnum *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - if (dest_type) ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_enum_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstEnumToInt *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_err_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstIntToErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_to_int_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstErrToInt *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_switch_prongs(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value, Stage1ZirInstCheckSwitchProngsRange *ranges, size_t range_count, - AstNode* else_prong, bool have_underscore_prong) -{ - Stage1ZirInstCheckSwitchProngs *instruction = heap::c_allocator.create(); - instruction->base.id = have_underscore_prong ? - Stage1ZirInstIdCheckSwitchProngsUnderYes : Stage1ZirInstIdCheckSwitchProngsUnderNo; - instruction->base.scope = scope; - instruction->base.source_node = source_node; - instruction->base.debug_id = irb_next_debug_id(ag); - instruction->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &instruction->base); - - instruction->target_value = target_value; - instruction->ranges = ranges; - instruction->range_count = range_count; - instruction->else_prong = else_prong; - - ir_ref_instruction(target_value, ag->current_basic_block); - for (size_t i = 0; i < range_count; i += 1) { - ir_ref_instruction(ranges[i].start, ag->current_basic_block); - ir_ref_instruction(ranges[i].end, ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_statement_is_void(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst* statement_value) -{ - Stage1ZirInstCheckStatementIsVoid *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->statement_value = statement_value; - - ir_ref_instruction(statement_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type_name(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value) -{ - Stage1ZirInstTypeName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_decl_ref(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { - Stage1ZirInstDeclRef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->tld = tld; - instruction->lval = lval; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_panic_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *msg) { - Stage1ZirInstPanic *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg = msg; - - ir_ref_instruction(msg, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_tag_name_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *target) { - Stage1ZirInstTagName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_parent_ptr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name, Stage1ZirInst *field_ptr) -{ - Stage1ZirInstFieldParentPtr *inst = ir_build_instruction( - ag, scope, source_node); - inst->type_value = type_value; - inst->field_name = field_name; - inst->field_ptr = field_ptr; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - ir_ref_instruction(field_ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_offset_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name) -{ - Stage1ZirInstOffsetOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_offset_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name) -{ - Stage1ZirInstBitOffsetOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type_info(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value) { - Stage1ZirInstTypeInfo *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_info) { - Stage1ZirInstType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_info = type_info; - - ir_ref_instruction(type_info, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_eval_branch_quota(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *new_quota) -{ - Stage1ZirInstSetEvalBranchQuota *instruction = ir_build_instruction(ag, scope, source_node); - instruction->new_quota = new_quota; - - ir_ref_instruction(new_quota, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align_bytes, Stage1ZirInst *target) -{ - Stage1ZirInstAlignCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align_bytes = align_bytes; - instruction->target = target; - - ir_ref_instruction(align_bytes, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_addrspace_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *addrspace, Stage1ZirInst *ptr) -{ - Stage1ZirInstAddrSpaceCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->addrspace = addrspace; - instruction->ptr = ptr; - - ir_ref_instruction(addrspace, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ResultLoc *result_loc, Stage1ZirInst *ty) -{ - Stage1ZirInstResolveResult *instruction = ir_build_instruction(ag, scope, source_node); - instruction->result_loc = result_loc; - instruction->ty = ty; - - if (ty != nullptr) ir_ref_instruction(ty, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_reset_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ResultLoc *result_loc) -{ - Stage1ZirInstResetResult *instruction = ir_build_instruction(ag, scope, source_node); - instruction->result_loc = result_loc; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_align_stack(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align_bytes) -{ - Stage1ZirInstSetAlignStack *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align_bytes = align_bytes; - - ir_ref_instruction(align_bytes, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_arg_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *fn_type, Stage1ZirInst *arg_index, bool allow_var) -{ - Stage1ZirInstArgType *instruction = heap::c_allocator.create(); - instruction->base.id = allow_var ? - Stage1ZirInstIdArgTypeAllowVarTrue : Stage1ZirInstIdArgTypeAllowVarFalse; - instruction->base.scope = scope; - instruction->base.source_node = source_node; - instruction->base.debug_id = irb_next_debug_id(ag); - instruction->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &instruction->base); - - instruction->fn_type = fn_type; - instruction->arg_index = arg_index; - - ir_ref_instruction(fn_type, ag->current_basic_block); - ir_ref_instruction(arg_index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_error_return_trace_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - IrInstErrorReturnTraceOptional optional) -{ - Stage1ZirInstErrorReturnTrace *inst = ir_build_instruction(ag, scope, source_node); - inst->optional = optional; - - return &inst->base; -} - -static Stage1ZirInst *ir_build_error_union(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *err_set, Stage1ZirInst *payload) -{ - Stage1ZirInstErrorUnion *instruction = ir_build_instruction(ag, scope, source_node); - instruction->err_set = err_set; - instruction->payload = payload; - - ir_ref_instruction(err_set, ag->current_basic_block); - ir_ref_instruction(payload, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_rmw_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *op, Stage1ZirInst *operand, - Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicRmw *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->op = op; - instruction->operand = operand; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - ir_ref_instruction(operand, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_load_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicLoad *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_store_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *value, Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicStore *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->value = value; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_save_err_ret_addr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstSaveErrRetAddr *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_add_implicit_return_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, ResultLocReturn *result_loc_ret) -{ - Stage1ZirInstAddImplicitReturnType *inst = ir_build_instruction(ag, scope, source_node); - inst->value = value; - inst->result_loc_ret = result_loc_ret; - - ir_ref_instruction(value, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_has_decl(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container, Stage1ZirInst *name) -{ - Stage1ZirInstHasDecl *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container = container; - instruction->name = name; - - ir_ref_instruction(container, ag->current_basic_block); - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_undeclared_identifier(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *name) { - Stage1ZirInstUndeclaredIdent *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_runtime_scope(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *scope_is_comptime, Stage1ZirInst *is_comptime) { - Stage1ZirInstCheckRuntimeScope *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scope_is_comptime = scope_is_comptime; - instruction->is_comptime = is_comptime; - - ir_ref_instruction(scope_is_comptime, ag->current_basic_block); - ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_union_init_named_field(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, Stage1ZirInst *field_result_loc, Stage1ZirInst *result_loc) -{ - Stage1ZirInstUnionInitNamedField *instruction = ir_build_instruction(ag, scope, source_node); - instruction->union_type = union_type; - instruction->field_name = field_name; - instruction->field_result_loc = field_result_loc; - instruction->result_loc = result_loc; - - ir_ref_instruction(union_type, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - ir_ref_instruction(field_result_loc, ag->current_basic_block); - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_alloca_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align, const char *name_hint, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstAlloca *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align = align; - instruction->name_hint = name_hint; - instruction->is_comptime = is_comptime; - - if (align != nullptr) ir_ref_instruction(align, ag->current_basic_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_end_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, ResultLoc *result_loc) -{ - Stage1ZirInstEndExpr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSuspendBegin *ir_build_suspend_begin_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - return ir_build_instruction(ag, scope, source_node); -} - -static Stage1ZirInst *ir_build_suspend_finish_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInstSuspendBegin *begin) -{ - Stage1ZirInstSuspendFinish *inst = ir_build_instruction(ag, scope, source_node); - inst->begin = begin; - - ir_ref_instruction(&begin->base, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_await_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *frame, ResultLoc *result_loc, bool is_nosuspend) -{ - Stage1ZirInstAwait *instruction = ir_build_instruction(ag, scope, source_node); - instruction->frame = frame; - instruction->result_loc = result_loc; - instruction->is_nosuspend = is_nosuspend; - - ir_ref_instruction(frame, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_resume_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *frame) { - Stage1ZirInstResume *instruction = ir_build_instruction(ag, scope, source_node); - instruction->frame = frame; - - ir_ref_instruction(frame, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSpillBegin *ir_build_spill_begin_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, SpillId spill_id) -{ - Stage1ZirInstSpillBegin *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->spill_id = spill_id; - - ir_ref_instruction(operand, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_spill_end_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInstSpillBegin *begin) -{ - Stage1ZirInstSpillEnd *instruction = ir_build_instruction(ag, scope, source_node); - instruction->begin = begin; - - ir_ref_instruction(&begin->base, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_wasm_memory_size_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *index) { - Stage1ZirInstWasmMemorySize *instruction = ir_build_instruction(ag, scope, source_node); - instruction->index = index; - - ir_ref_instruction(index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_wasm_memory_grow_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *index, Stage1ZirInst *delta) { - Stage1ZirInstWasmMemoryGrow *instruction = ir_build_instruction(ag, scope, source_node); - instruction->index = index; - instruction->delta = delta; - - ir_ref_instruction(index, ag->current_basic_block); - ir_ref_instruction(delta, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstSrc *instruction = ir_build_instruction(ag, scope, source_node); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_prefetch(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *options) -{ - Stage1ZirInstPrefetch *prefetch_instruction = ir_build_instruction( - ag, scope, source_node); - prefetch_instruction->ptr = ptr; - prefetch_instruction->options = options; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &prefetch_instruction->base; -} - - -static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) { - results[ReturnKindUnconditional] = 0; - results[ReturnKindError] = 0; - - Scope *scope = inner_scope; - - while (scope != outer_scope) { - assert(scope); - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - results[defer_kind] += 1; - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } -} - -static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, Stage1ZirInst *err_value) { - Scope *scope = inner_scope; - if (is_noreturn != nullptr) *is_noreturn = false; - while (scope != outer_scope) { - if (!scope) - return true; - - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - AstNode *defer_expr_node = defer_node->data.defer.expr; - AstNode *defer_var_node = defer_node->data.defer.err_payload; - - if (defer_kind == ReturnKindError && err_value == nullptr) { - // This is an `errdefer` but we're generating code for a - // `return` that doesn't return an error, skip it - scope = scope->parent; - continue; - } - - Scope *defer_expr_scope = defer_node->data.defer.expr_scope; - if (defer_var_node != nullptr) { - assert(defer_kind == ReturnKindError); - assert(defer_var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(defer_var_node); - - if (defer_expr_node->type == NodeTypeUnreachable) { - add_node_error(ag->codegen, defer_var_node, - buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return false; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, defer_expr_scope)) { - is_comptime = ir_build_const_bool(ag, defer_expr_scope, - defer_expr_node, true); - } else { - is_comptime = ir_build_test_comptime(ag, defer_expr_scope, - defer_expr_node, err_value); - } - - ZigVar *err_var = ir_create_var(ag, defer_var_node, defer_expr_scope, - var_name, true, true, false, is_comptime); - build_decl_var_and_init(ag, defer_expr_scope, defer_var_node, err_var, err_value, - buf_ptr(var_name), is_comptime); - - defer_expr_scope = err_var->child_scope; - } - - Stage1ZirInst *defer_expr_value = astgen_node(ag, defer_expr_node, defer_expr_scope); - if (defer_expr_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (instr_is_unreachable(defer_expr_value)) { - if (is_noreturn != nullptr) *is_noreturn = true; - } else { - ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node, - defer_expr_value); - } - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return true; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } - return true; -} - -static void ir_set_cursor_at_end(Stage1AstGen *ag, Stage1ZirBasicBlock *basic_block) { - assert(basic_block); - ag->current_basic_block = basic_block; -} - -static void ir_set_cursor_at_end_and_append_block(Stage1AstGen *ag, Stage1ZirBasicBlock *basic_block) { - basic_block->index = ag->exec->basic_block_list.length; - ag->exec->basic_block_list.append(basic_block); - ir_set_cursor_at_end(ag, basic_block); -} - -static ScopeSuspend *get_scope_suspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdSuspend) - return (ScopeSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDeferExpr) - return (ScopeDeferExpr *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static Stage1ZirInst *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeReturnExpr); - - ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); - if (scope_defer_expr) { - if (!scope_defer_expr->reported_err) { - add_node_error(ag->codegen, node, buf_sprintf("cannot return from defer expression")); - scope_defer_expr->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Scope *outer_scope = ag->exec->begin_scope; - - AstNode *expr_node = node->data.return_expr.expr; - switch (node->data.return_expr.kind) { - case ReturnKindUnconditional: - { - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - - Stage1ZirInst *return_value; - if (expr_node) { - // Temporarily set this so that if we return a type it gets the name of the function - ZigFn *prev_name_fn = ag->exec->name_fn; - ag->exec->name_fn = ag->fn; - return_value = astgen_node_extra(ag, expr_node, scope, LValNone, &result_loc_ret->base); - ag->exec->name_fn = prev_name_fn; - if (return_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - return_value = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, return_value, &result_loc_ret->base); - } - - ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret); - - size_t defer_counts[2]; - ir_count_defers(ag, scope, outer_scope, defer_counts); - bool have_err_defers = defer_counts[ReturnKindError] > 0; - if (!have_err_defers && !ag->codegen->have_err_ret_tracing) { - // only generate unconditional defers - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - Stage1ZirInst *result = ir_build_return_src(ag, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - bool should_inline = ir_should_inline(ag->exec, scope); - - Stage1ZirBasicBlock *err_block = ir_create_basic_block(ag, scope, "ErrRetErr"); - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, scope, "ErrRetOk"); - - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node, return_value, false, true); - - Stage1ZirInst *is_comptime; - if (should_inline) { - is_comptime = ir_build_const_bool(ag, scope, node, should_inline); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_err); - } - - ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime); - Stage1ZirBasicBlock *ret_stmt_block = ir_create_basic_block(ag, scope, "RetStmt"); - - ir_set_cursor_at_end_and_append_block(ag, err_block); - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, return_value)) - return ag->codegen->invalid_inst_src; - if (ag->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(ag, scope, node); - } - ir_build_br(ag, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - ir_build_br(ag, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ret_stmt_block); - Stage1ZirInst *result = ir_build_return_src(ag, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - case ReturnKindError: - { - assert(expr_node); - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirInst *is_err_val = ir_build_test_err_src(ag, scope, node, err_union_ptr, true, false); - - Stage1ZirBasicBlock *return_block = ir_create_basic_block(ag, scope, "ErrRetReturn"); - Stage1ZirBasicBlock *continue_block = ir_create_basic_block(ag, scope, "ErrRetContinue"); - Stage1ZirInst *is_comptime; - bool should_inline = ir_should_inline(ag->exec, scope); - if (should_inline) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_err_val); - } - ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, return_block); - Stage1ZirInst *err_val_ptr = ir_build_unwrap_err_code_src(ag, scope, node, err_union_ptr); - Stage1ZirInst *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr); - ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr); - Stage1ZirInstSpillBegin *spill_begin = ir_build_spill_begin_src(ag, scope, node, err_val, - SpillIdRetErrCode); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - ir_build_end_expr(ag, scope, node, err_val, &result_loc_ret->base); - - bool is_noreturn = false; - if (!astgen_defers_for_block(ag, scope, outer_scope, &is_noreturn, err_val)) { - return ag->codegen->invalid_inst_src; - } - if (!is_noreturn) { - if (ag->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(ag, scope, node); - } - err_val = ir_build_spill_end_src(ag, scope, node, spill_begin); - Stage1ZirInst *ret_inst = ir_build_return_src(ag, scope, node, err_val); - result_loc_ret->base.source_instruction = ret_inst; - } - - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, scope, node, err_union_ptr, false, false); - if (lval == LValPtr) - return unwrapped_ptr; - else - return ir_expr_wrap(ag, scope, ir_build_load_ptr(ag, scope, node, unwrapped_ptr), result_loc); - } - } - zig_unreachable(); -} - -ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime, - bool skip_name_check) -{ - ZigVar *variable_entry = heap::c_allocator.create(); - variable_entry->parent_scope = parent_scope; - variable_entry->shadowable = is_shadowable; - variable_entry->is_comptime = is_comptime; - variable_entry->src_arg_index = SIZE_MAX; - variable_entry->const_value = codegen->pass1_arena->create(); - - if (is_comptime != nullptr) { - is_comptime->ref_count += 1; - } - - if (name) { - variable_entry->name = strdup(buf_ptr(name)); - - if (!skip_name_check) { - ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr); - if (existing_var && !existing_var->shadowable) { - if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); - add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration here")); - } - variable_entry->var_type = codegen->builtin_types.entry_invalid; - } - } - } else { - assert(is_shadowable); - // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" - // might already be solved, let's just make sure it has test coverage - // maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables - variable_entry->name = "_anon"; - } - - variable_entry->src_is_const = src_is_const; - variable_entry->gen_is_const = gen_is_const; - variable_entry->decl_node = node; - variable_entry->child_scope = create_var_scope(codegen, node, parent_scope, variable_entry); - - return variable_entry; -} - - -// Set name to nullptr to make the variable anonymous (not visible to programmer). -// After you call this function var->child_scope has the variable in scope -static ZigVar *ir_create_var(Stage1AstGen *ag, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime) -{ - bool is_underscored = name ? buf_eql_str(name, "_") : false; - ZigVar *var = create_local_var(ag->codegen, node, scope, - (is_underscored ? nullptr : name), src_is_const, gen_is_const, - (is_underscored ? true : is_shadowable), is_comptime, false); - assert(var->child_scope); - return var; -} - -static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { - ResultLocPeer *result = heap::c_allocator.create(); - result->base.id = ResultLocIdPeer; - result->base.source_instruction = peer_parent->base.source_instruction; - result->parent = peer_parent; - result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const; - return result; -} - -static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) { - if (name == nullptr) return false; - - for (;;) { - if (scope == nullptr || scope->id == ScopeIdFnDef) { - break; - } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) { - Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name; - if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) { - ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name))); - add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration here")); - return true; - } - } - scope = scope->parent; - } - return false; -} - -static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *block_node, LVal lval, - ResultLoc *result_loc) -{ - assert(block_node->type == NodeTypeBlock); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, parent_scope, block_node, block_node->data.block.name)) - return ag->codegen->invalid_inst_src; - - ScopeBlock *scope_block = create_block_scope(ag->codegen, block_node, parent_scope); - - Scope *outer_block_scope = &scope_block->base; - Scope *child_scope = outer_block_scope; - - ZigFn *fn_entry = scope_fn_entry(parent_scope); - if (fn_entry && fn_entry->child_scope == parent_scope) { - fn_entry->def_scope = scope_block; - } - - if (block_node->data.block.statements.length == 0) { - if (scope_block->name != nullptr) { - add_node_error(ag->codegen, block_node, buf_sprintf("unused block label")); - } - // {} - return ir_lval_wrap(ag, parent_scope, ir_build_const_void(ag, child_scope, block_node), lval, result_loc); - } - - if (block_node->data.block.name != nullptr) { - scope_block->lval = lval; - scope_block->incoming_blocks = &incoming_blocks; - scope_block->incoming_values = &incoming_values; - scope_block->end_block = ir_create_basic_block(ag, parent_scope, "BlockEnd"); - scope_block->is_comptime = ir_build_const_bool(ag, parent_scope, block_node, - ir_should_inline(ag->exec, parent_scope)); - - scope_block->peer_parent = heap::c_allocator.create(); - scope_block->peer_parent->base.id = ResultLocIdPeerParent; - scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; - scope_block->peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - scope_block->peer_parent->end_bb = scope_block->end_block; - scope_block->peer_parent->is_comptime = scope_block->is_comptime; - scope_block->peer_parent->parent = result_loc; - ir_build_reset_result(ag, parent_scope, block_node, &scope_block->peer_parent->base); - } - - bool is_continuation_unreachable = false; - bool found_invalid_inst = false; - Stage1ZirInst *noreturn_return_value = nullptr; - for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { - AstNode *statement_node = block_node->data.block.statements.at(i); - - Stage1ZirInst *statement_value = astgen_node(ag, statement_node, child_scope); - if (statement_value == ag->codegen->invalid_inst_src) { - // keep generating all the elements of the block in case of error, - // we want to collect other compile errors - found_invalid_inst = true; - continue; - } - - is_continuation_unreachable = instr_is_unreachable(statement_value); - if (is_continuation_unreachable) { - // keep the last noreturn statement value around in case we need to return it - noreturn_return_value = statement_value; - } - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (statement_node->type == NodeTypeDefer) { - // defer starts a new scope - child_scope = statement_node->data.defer.child_scope; - assert(child_scope); - } else if (statement_value->id == Stage1ZirInstIdDeclVar) { - // variable declarations start a new scope - Stage1ZirInstDeclVar *decl_var_instruction = (Stage1ZirInstDeclVar *)statement_value; - child_scope = decl_var_instruction->var->child_scope; - } else if (!is_continuation_unreachable) { - // this statement's value must be void - ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value); - } - } - - if (scope_block->name != nullptr && scope_block->name_used == false) { - add_node_error(ag->codegen, block_node, buf_sprintf("unused block label")); - } - - if (found_invalid_inst) - return ag->codegen->invalid_inst_src; - - if (is_continuation_unreachable) { - assert(noreturn_return_value != nullptr); - if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) { - return noreturn_return_value; - } - - if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block); - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - return ir_expr_wrap(ag, parent_scope, phi, result_loc); - } else { - incoming_blocks.append(ag->current_basic_block); - Stage1ZirInst *else_expr_result = ir_build_const_void(ag, parent_scope, block_node); - - if (scope_block->peer_parent != nullptr) { - ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent); - scope_block->peer_parent->peers.append(peer_result); - ir_build_end_expr(ag, parent_scope, block_node, else_expr_result, &peer_result->base); - - if (scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - } - - incoming_values.append(else_expr_result); - } - - bool is_return_from_fn = block_node == ag->main_block_node; - if (!is_return_from_fn) { - if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *result; - if (block_node->data.block.name != nullptr) { - ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime); - ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block); - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - result = ir_expr_wrap(ag, parent_scope, phi, result_loc); - } else { - Stage1ZirInst *void_inst = ir_build_const_void(ag, child_scope, block_node); - result = ir_lval_wrap(ag, parent_scope, void_inst, lval, result_loc); - } - if (!is_return_from_fn) - return result; - - // no need for save_err_ret_addr because this cannot return error - // only generate unconditional defers - - ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, parent_scope, block_node, &result_loc_ret->base); - ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base); - if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - return ir_build_return_src(ag, child_scope, result->source_node, result); -} - -static Stage1ZirInst *astgen_bin_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) { - Scope *inner_scope = scope; - if (op_id == IrBinOpArrayCat || op_id == IrBinOpArrayMult) { - inner_scope = create_comptime_scope(ag->codegen, node, scope); - } - - Stage1ZirInst *op1 = astgen_node(ag, node->data.bin_op_expr.op1, inner_scope); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, inner_scope); - - if (op1 == ag->codegen->invalid_inst_src || op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_bin_op(ag, scope, node, op_id, op1, op2, true); -} - -static Stage1ZirInst *astgen_merge_err_sets(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Stage1ZirInst *op1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - - if (op1 == ag->codegen->invalid_inst_src || op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - // TODO only pass type_name when the || operator is the top level AST node in the var decl expr - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", scope, node, &bare_name, nullptr); - - return ir_build_merge_err_sets(ag, scope, node, op1, op2, type_name); -} - -static Stage1ZirInst *astgen_assign(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Stage1ZirInst *lvalue = astgen_node_extra(ag, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = lvalue; - ir_ref_instruction(lvalue, ag->current_basic_block); - ir_build_reset_result(ag, scope, node, &result_loc_inst->base); - - Stage1ZirInst *rvalue = astgen_node_extra(ag, node->data.bin_op_expr.op2, scope, LValNone, - &result_loc_inst->base); - if (rvalue == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_const_void(ag, scope, node); -} - -static Stage1ZirInst *astgen_assign_op(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) { - Stage1ZirInst *lvalue = astgen_node_extra(ag, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == ag->codegen->invalid_inst_src) - return lvalue; - Stage1ZirInst *op1 = ir_build_load_ptr(ag, scope, node->data.bin_op_expr.op1, lvalue); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (op2 == ag->codegen->invalid_inst_src) - return op2; - Stage1ZirInst *result = ir_build_bin_op(ag, scope, node, op_id, op1, op2, true); - ir_build_store_ptr(ag, scope, node, lvalue, result); - return ir_build_const_void(ag, scope, node); -} - -static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - Stage1ZirInst *val1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - if (val1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val1_block = ag->current_basic_block; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, val1); - } - - // block for when val1 == false - Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolOrFalse"); - // block for when val1 == true (don't even evaluate the second part) - Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolOrTrue"); - - Stage1ZirInst *val1_true = ir_build_const_bool(ag, scope, node, true); - ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, false_block); - Stage1ZirInst *val2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (val2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val2_block = ag->current_basic_block; - - ir_build_br(ag, scope, node, true_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, true_block); - - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1_true; - incoming_values[1] = val2; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - const bool merge_comptime = true; - return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr); -} - -static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - Stage1ZirInst *val1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - if (val1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val1_block = ag->current_basic_block; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, val1); - } - - // block for when val1 == true - Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolAndTrue"); - // block for when val1 == false (don't even evaluate the second part) - Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolAndFalse"); - - Stage1ZirInst *val1_false = ir_build_const_bool(ag, scope, node, false); - ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, true_block); - Stage1ZirInst *val2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (val2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val2_block = ag->current_basic_block; - - ir_build_br(ag, scope, node, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, false_block); - - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1_false; - incoming_values[1] = val2; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - const bool merge_comptime = true; - return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr); -} - -static ResultLocPeerParent *ir_build_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst, - Stage1ZirBasicBlock *end_block, ResultLoc *parent, Stage1ZirInst *is_comptime) -{ - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.source_instruction = cond_br_inst; - peer_parent->base.allow_write_through_const = parent->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = parent; - - Stage1ZirInst *popped_inst = ag->current_basic_block->instruction_list.pop(); - ir_assert(popped_inst == cond_br_inst, cond_br_inst); - - ir_build_reset_result(ag, cond_br_inst->scope, cond_br_inst->source_node, &peer_parent->base); - ag->current_basic_block->instruction_list.append(popped_inst); - - return peer_parent; -} - -static ResultLocPeerParent *ir_build_binary_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst, - Stage1ZirBasicBlock *else_block, Stage1ZirBasicBlock *end_block, ResultLoc *parent, Stage1ZirInst *is_comptime) -{ - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, parent, is_comptime); - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = else_block; - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = end_block; - - return peer_parent; -} - -static Stage1ZirInst *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - Stage1ZirInst *maybe_ptr = astgen_node_extra(ag, op1_node, parent_scope, LValPtr, nullptr); - if (maybe_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, parent_scope, node, maybe_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, parent_scope, node, maybe_val); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, parent_scope)) { - is_comptime = ir_build_const_bool(ag, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, parent_scope, node, is_non_null); - } - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, parent_scope, "OptionalNonNull"); - Stage1ZirBasicBlock *null_block = ir_create_basic_block(ag, parent_scope, "OptionalNull"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "OptionalEnd"); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, ok_block, end_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, null_block); - Stage1ZirInst *null_result = astgen_node_extra(ag, op2_node, parent_scope, LValNone, - &peer_parent->peers.at(0)->base); - if (null_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_null_block = ag->current_basic_block; - if (!instr_is_unreachable(null_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - Stage1ZirInst *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, parent_scope, node, maybe_ptr, false); - Stage1ZirInst *unwrapped_payload = ir_build_load_ptr(ag, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(ag, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - Stage1ZirBasicBlock *after_ok_block = ag->current_basic_block; - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, end_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = null_result; - incoming_values[1] = unwrapped_payload; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_null_block; - incoming_blocks[1] = after_ok_block; - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static Stage1ZirInst *astgen_error_union(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - Stage1ZirInst *err_set = astgen_node(ag, op1_node, parent_scope); - if (err_set == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *payload = astgen_node(ag, op2_node, parent_scope); - if (payload == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_error_union(ag, parent_scope, node, err_set, payload); -} - -static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeBinOpExpr); - - BinOpType bin_op_type = node->data.bin_op_expr.bin_op; - switch (bin_op_type) { - case BinOpTypeInvalid: - zig_unreachable(); - case BinOpTypeAssign: - return ir_lval_wrap(ag, scope, astgen_assign(ag, scope, node), lval, result_loc); - case BinOpTypeAssignTimes: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeAssignTimesWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeAssignTimesSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultSat), lval, result_loc); - case BinOpTypeAssignDiv: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeAssignMod: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeAssignPlus: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAssignPlusWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeAssignPlusSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddSat), lval, result_loc); - case BinOpTypeAssignMinus: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeAssignMinusWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeAssignMinusSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubSat), lval, result_loc); - case BinOpTypeAssignBitShiftLeft: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeAssignBitShiftLeftSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpShlSat), lval, result_loc); - case BinOpTypeAssignBitShiftRight: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAssignBitAnd: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeAssignBitXor: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeAssignBitOr: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBoolOr: - return ir_lval_wrap(ag, scope, astgen_bool_or(ag, scope, node), lval, result_loc); - case BinOpTypeBoolAnd: - return ir_lval_wrap(ag, scope, astgen_bool_and(ag, scope, node), lval, result_loc); - case BinOpTypeCmpEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpEq), lval, result_loc); - case BinOpTypeCmpNotEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpNotEq), lval, result_loc); - case BinOpTypeCmpLessThan: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpLessThan), lval, result_loc); - case BinOpTypeCmpGreaterThan: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpGreaterThan), lval, result_loc); - case BinOpTypeCmpLessOrEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpLessOrEq), lval, result_loc); - case BinOpTypeCmpGreaterOrEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpGreaterOrEq), lval, result_loc); - case BinOpTypeBinOr: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBinXor: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeBinAnd: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeBitShiftLeft: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeBitShiftLeftSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpShlSat), lval, result_loc); - case BinOpTypeBitShiftRight: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAdd: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAddWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeAddSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddSat), lval, result_loc); - case BinOpTypeSub: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeSubWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeSubSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubSat), lval, result_loc); - case BinOpTypeMult: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeMultWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeMultSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultSat), lval, result_loc); - case BinOpTypeDiv: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeMod: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeArrayCat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpArrayCat), lval, result_loc); - case BinOpTypeArrayMult: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpArrayMult), lval, result_loc); - case BinOpTypeMergeErrorSets: - return ir_lval_wrap(ag, scope, astgen_merge_err_sets(ag, scope, node), lval, result_loc); - case BinOpTypeUnwrapOptional: - return astgen_orelse(ag, scope, node, lval, result_loc); - case BinOpTypeErrorUnion: - return ir_lval_wrap(ag, scope, astgen_error_union(ag, scope, node), lval, result_loc); - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_int_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeIntLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - BigInt bigint; - token_number_literal_bigint(root_struct, &bigint, node->main_token); - return ir_build_const_bigint(ag, scope, node, bigint); -} - -static Stage1ZirInst *astgen_float_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeFloatLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; - - BigFloat bigfloat; - if ((err = bigfloat_init_buf(&bigfloat, (const uint8_t *)source + byte_offset))) { - add_node_error(ag->codegen, node, buf_sprintf("float literal out of range of any type")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_const_bigfloat(ag, scope, node, bigfloat); -} - -static Stage1ZirInst *astgen_char_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeCharLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; - - src_assert(source[byte_offset] == '\'', node); - byte_offset += 1; - - uint32_t codepoint; - size_t bad_index; - if ((err = source_char_literal(source + byte_offset, &codepoint, &bad_index))) { - add_node_error(ag->codegen, node, buf_sprintf("invalid character")); - return ag->codegen->invalid_inst_src; - } - return ir_build_const_uint(ag, scope, node, codepoint); -} - -static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - Error err; - assert(node->type == NodeTypeIdentifier); - - bool is_at_syntax; - Buf *variable_name = node_identifier_buf2(node, &is_at_syntax); - - if (!is_at_syntax) { - if (buf_eql_str(variable_name, "_")) { - if (lval == LValAssign) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = get_pointer_to_type(ag->codegen, - ag->codegen->builtin_types.entry_void, false); - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; - return &const_instruction->base; - } - } - - { - Stage1ZirInst *value = nullptr; - if (buf_eql_str(variable_name, "null")) { - value = ir_build_const_null(ag, scope, node); - } else if (buf_eql_str(variable_name, "true")) { - value = ir_build_const_bool(ag, scope, node, true); - } else if (buf_eql_str(variable_name, "false")) { - value = ir_build_const_bool(ag, scope, node, false); - } else if (buf_eql_str(variable_name, "undefined")) { - value = ir_build_const_undefined(ag, scope, node); - } - - if (value != nullptr) { - if (lval == LValPtr || lval == LValAssign) { - return ir_build_ref_src(ag, scope, node, value); - } else { - return ir_expr_wrap(ag, scope, value, result_loc); - } - } - } - - ZigType *primitive_type; - if ((err = get_primitive_type(ag->codegen, variable_name, &primitive_type))) { - if (err == ErrorOverflow) { - add_node_error(ag->codegen, node, - buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", - buf_ptr(variable_name))); - return ag->codegen->invalid_inst_src; - } - assert(err == ErrorPrimitiveTypeNotFound); - } else { - Stage1ZirInst *value = ir_build_const_type(ag, scope, node, primitive_type); - if (lval == LValPtr || lval == LValAssign) { - return ir_build_ref_src(ag, scope, node, value); - } else { - return ir_expr_wrap(ag, scope, value, result_loc); - } - } - } - - ScopeFnDef *crossed_fndef_scope; - ZigVar *var = find_variable(ag->codegen, scope, variable_name, &crossed_fndef_scope); - if (var) { - Stage1ZirInst *var_ptr = ir_build_var_ptr_x(ag, scope, node, var, crossed_fndef_scope); - if (lval == LValPtr || lval == LValAssign) { - return var_ptr; - } else { - return ir_expr_wrap(ag, scope, ir_build_load_ptr(ag, scope, node, var_ptr), result_loc); - } - } - - Tld *tld = nullptr; - { - Scope *s = scope; - while (s) { - if (s->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)s; - - Tld *result = find_container_decl(ag->codegen, decls_scope, variable_name); - if (result != nullptr) { - if (tld != nullptr && tld != result) { - ErrorMsg *msg = add_node_error(ag->codegen, node, - buf_sprintf("ambiguous reference")); - add_error_note(ag->codegen, msg, tld->source_node, - buf_sprintf("declared here")); - add_error_note(ag->codegen, msg, result->source_node, - buf_sprintf("also declared here")); - return ag->codegen->invalid_inst_src; - } - tld = result; - } - } - s = s->parent; - } - } - - if (tld) { - Stage1ZirInst *decl_ref = ir_build_decl_ref(ag, scope, node, tld, lval); - if (lval == LValPtr || lval == LValAssign) { - return decl_ref; - } else { - return ir_expr_wrap(ag, scope, decl_ref, result_loc); - } - } - - if (get_container_scope(node->owner)->any_imports_failed) { - // skip the error message since we had a failing import in this file - // if an import breaks we don't need redundant undeclared identifier errors - return ag->codegen->invalid_inst_src; - } - - return ir_build_undeclared_identifier(ag, scope, node, variable_name); -} - -static Stage1ZirInst *astgen_array_access(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeArrayAccessExpr); - - AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - Stage1ZirInst *array_ref_instruction = astgen_node_extra(ag, array_ref_node, scope, LValPtr, nullptr); - if (array_ref_instruction == ag->codegen->invalid_inst_src) - return array_ref_instruction; - - // Create an usize-typed result location to hold the subscript value, this - // makes it possible for the compiler to infer the subscript expression type - // if needed - Stage1ZirInst *usize_type_inst = ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_usize); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, usize_type_inst, no_result_loc()); - - AstNode *subscript_node = node->data.array_access_expr.subscript; - Stage1ZirInst *subscript_value = astgen_node_extra(ag, subscript_node, scope, LValNone, &result_loc_cast->base); - if (subscript_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *subscript_instruction = ir_build_implicit_cast(ag, scope, subscript_node, subscript_value, result_loc_cast); - - Stage1ZirInst *ptr_instruction = ir_build_elem_ptr(ag, scope, node, array_ref_instruction, - subscript_instruction, true, PtrLenSingle, nullptr); - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); -} - -static Stage1ZirInst *astgen_field_access(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFieldAccessExpr); - - AstNode *container_ref_node = node->data.field_access_expr.struct_expr; - Buf *field_name = node->data.field_access_expr.field_name; - - Stage1ZirInst *container_ref_instruction = astgen_node_extra(ag, container_ref_node, scope, LValPtr, nullptr); - if (container_ref_instruction == ag->codegen->invalid_inst_src) - return container_ref_instruction; - - return ir_build_field_ptr(ag, scope, node, container_ref_instruction, field_name, false); -} - -static Stage1ZirInst *astgen_overflow_op(Stage1AstGen *ag, Scope *scope, AstNode *node, IrOverflowOp op) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3); - - - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op1 = astgen_node(ag, op1_node, scope); - if (op1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op2 = astgen_node(ag, op2_node, scope); - if (op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *result_ptr = astgen_node(ag, result_ptr_node, scope); - if (result_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_overflow_op_src(ag, scope, node, op, type_value, op1, op2, result_ptr); -} - -static Stage1ZirInst *astgen_mul_add(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *op3_node = node->data.fn_call_expr.params.at(3); - - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op1 = astgen_node(ag, op1_node, scope); - if (op1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op2 = astgen_node(ag, op2_node, scope); - if (op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op3 = astgen_node(ag, op3_node, scope); - if (op3 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_mul_add_src(ag, scope, node, type_value, op1, op2, op3); -} - -static Stage1ZirInst *astgen_this(Stage1AstGen *ag, Scope *orig_scope, AstNode *node) { - for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { - if (it_scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)it_scope; - ZigType *container_type = decls_scope->container_type; - if (container_type != nullptr) { - return ir_build_const_type(ag, orig_scope, node, container_type); - } else { - return ir_build_const_import(ag, orig_scope, node, decls_scope->import); - } - } - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_async_call(Stage1AstGen *ag, Scope *scope, AstNode *await_node, AstNode *call_node, - LVal lval, ResultLoc *result_loc) -{ - if (call_node->data.fn_call_expr.params.length != 4) { - add_node_error(ag->codegen, call_node, - buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, - call_node->data.fn_call_expr.params.length)); - return ag->codegen->invalid_inst_src; - } - - AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); - Stage1ZirInst *bytes = astgen_node(ag, bytes_node, scope); - if (bytes == ag->codegen->invalid_inst_src) - return bytes; - - AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); - Stage1ZirInst *ret_ptr = astgen_node(ag, ret_ptr_node, scope); - if (ret_ptr == ag->codegen->invalid_inst_src) - return ret_ptr; - - AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; - bool is_async_call_builtin = true; - AstNode *args_node = call_node->data.fn_call_expr.params.at(3); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - size_t arg_count = args_node->data.container_init_expr.entries.length; - Stage1ZirInst **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); - Stage1ZirInst *arg = astgen_node(ag, arg_node, scope); - if (arg == ag->codegen->invalid_inst_src) - return arg; - args[i] = arg; - } - - Stage1ZirInst *call = ir_build_call_src(ag, scope, call_node, nullptr, fn_ref, arg_count, args, - ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); - } else { - exec_add_error_node(ag->codegen, ag->exec, args_node, - buf_sprintf("TODO: @asyncCall with anon struct literal")); - return ag->codegen->invalid_inst_src; - } - } - Stage1ZirInst *args = astgen_node(ag, args_node, scope); - if (args == ag->codegen->invalid_inst_src) - return args; - - Stage1ZirInst *call = ir_build_async_call_extra(ag, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); -} - -static Stage1ZirInst *astgen_fn_call_with_args(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - AstNode *fn_ref_node, CallModifier modifier, Stage1ZirInst *options, - AstNode **args_ptr, size_t args_len, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - Stage1ZirInst *fn_type = ir_build_typeof_1(ag, scope, source_node, fn_ref); - - Stage1ZirInst **args = heap::c_allocator.allocate(args_len); - for (size_t i = 0; i < args_len; i += 1) { - AstNode *arg_node = args_ptr[i]; - - Stage1ZirInst *arg_index = ir_build_const_usize(ag, scope, arg_node, i); - Stage1ZirInst *arg_type = ir_build_arg_type(ag, scope, source_node, fn_type, arg_index, true); - ResultLoc *no_result = no_result_loc(); - ir_build_reset_result(ag, scope, source_node, no_result); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, arg_type, no_result); - - Stage1ZirInst *arg = astgen_node_extra(ag, arg_node, scope, LValNone, &result_loc_cast->base); - if (arg == ag->codegen->invalid_inst_src) - return arg; - - args[i] = ir_build_implicit_cast(ag, scope, arg_node, arg, result_loc_cast); - } - - Stage1ZirInst *fn_call; - if (options != nullptr) { - fn_call = ir_build_call_args(ag, scope, source_node, options, fn_ref, args, args_len, result_loc); - } else { - fn_call = ir_build_call_src(ag, scope, source_node, nullptr, fn_ref, args_len, args, nullptr, - modifier, false, nullptr, result_loc); - } - return ir_lval_wrap(ag, scope, fn_call, lval, result_loc); -} - -static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(ag->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return ag->codegen->invalid_inst_src; - } - - BuiltinFnEntry *builtin_fn = entry->value; - size_t actual_param_count = node->data.fn_call_expr.params.length; - - if (builtin_fn->param_count != SIZE_MAX && builtin_fn->param_count != actual_param_count) { - add_node_error(ag->codegen, node, - buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize, - builtin_fn->param_count, actual_param_count)); - return ag->codegen->invalid_inst_src; - } - - switch (builtin_fn->id) { - case BuiltinFnIdInvalid: - zig_unreachable(); - case BuiltinFnIdTypeof: - { - Scope *sub_scope = create_typeof_scope(ag->codegen, node, scope); - - size_t arg_count = node->data.fn_call_expr.params.length; - - Stage1ZirInst *type_of; - - if (arg_count == 0) { - add_node_error(ag->codegen, node, - buf_sprintf("expected at least 1 argument, found 0")); - return ag->codegen->invalid_inst_src; - } else if (arg_count == 1) { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, sub_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - type_of = ir_build_typeof_1(ag, scope, node, arg0_value); - } else { - Stage1ZirInst **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - Stage1ZirInst *arg = astgen_node(ag, arg_node, sub_scope); - if (arg == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - args[i] = arg; - } - - type_of = ir_build_typeof_n(ag, scope, node, args, arg_count); - } - return ir_lval_wrap(ag, scope, type_of, lval, result_loc); - } - case BuiltinFnIdSetCold: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_cold = ir_build_set_cold(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_cold, lval, result_loc); - } - case BuiltinFnIdSetRuntimeSafety: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_safety = ir_build_set_runtime_safety(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_safety, lval, result_loc); - } - case BuiltinFnIdSetFloatMode: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_float_mode = ir_build_set_float_mode(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_float_mode, lval, result_loc); - } - case BuiltinFnIdSizeof: - case BuiltinFnIdBitSizeof: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *size_of = ir_build_size_of(ag, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof); - return ir_lval_wrap(ag, scope, size_of, lval, result_loc); - } - case BuiltinFnIdImport: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *import = ir_build_import(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, import, lval, result_loc); - } - case BuiltinFnIdCImport: - { - Stage1ZirInst *c_import = ir_build_c_import(ag, scope, node); - return ir_lval_wrap(ag, scope, c_import, lval, result_loc); - } - case BuiltinFnIdCInclude: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C include valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_include = ir_build_c_include(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, c_include, lval, result_loc); - } - case BuiltinFnIdCDefine: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C define valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_define = ir_build_c_define(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, c_define, lval, result_loc); - } - case BuiltinFnIdCUndef: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C undef valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_undef = ir_build_c_undef(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, c_undef, lval, result_loc); - } - case BuiltinFnIdCompileErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *compile_err = ir_build_compile_err(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, compile_err, lval, result_loc); - } - case BuiltinFnIdCompileLog: - { - Stage1ZirInst **args = heap::c_allocator.allocate(actual_param_count); - - for (size_t i = 0; i < actual_param_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - args[i] = astgen_node(ag, arg_node, scope); - if (args[i] == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *compile_log = ir_build_compile_log(ag, scope, node, actual_param_count, args); - return ir_lval_wrap(ag, scope, compile_log, lval, result_loc); - } - case BuiltinFnIdErrName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *err_name = ir_build_err_name(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, err_name, lval, result_loc); - } - case BuiltinFnIdEmbedFile: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *embed_file = ir_build_embed_file(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, embed_file, lval, result_loc); - } - case BuiltinFnIdCmpxchgWeak: - case BuiltinFnIdCmpxchgStrong: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - Stage1ZirInst *arg4_value = astgen_node(ag, arg4_node, scope); - if (arg4_value == ag->codegen->invalid_inst_src) - return arg4_value; - - AstNode *arg5_node = node->data.fn_call_expr.params.at(5); - Stage1ZirInst *arg5_value = astgen_node(ag, arg5_node, scope); - if (arg5_value == ag->codegen->invalid_inst_src) - return arg5_value; - - Stage1ZirInst *cmpxchg = ir_build_cmpxchg_src(ag, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), - result_loc); - return ir_lval_wrap(ag, scope, cmpxchg, lval, result_loc); - } - case BuiltinFnIdFence: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *fence = ir_build_fence(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, fence, lval, result_loc); - } - case BuiltinFnIdReduce: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *reduce = ir_build_reduce(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, reduce, lval, result_loc); - } - case BuiltinFnIdDivExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivTrunc: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivFloor: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdRem: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdMod: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSqrt: - case BuiltinFnIdSin: - case BuiltinFnIdCos: - case BuiltinFnIdTan: - case BuiltinFnIdExp: - case BuiltinFnIdExp2: - case BuiltinFnIdLog: - case BuiltinFnIdLog2: - case BuiltinFnIdLog10: - case BuiltinFnIdFabs: - case BuiltinFnIdFloor: - case BuiltinFnIdCeil: - case BuiltinFnIdTrunc: - case BuiltinFnIdNearbyInt: - case BuiltinFnIdRound: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *inst = ir_build_float_op_src(ag, scope, node, arg0_value, builtin_fn->id); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdTruncate: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *truncate = ir_build_truncate(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, truncate, lval, result_loc); - } - case BuiltinFnIdIntCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_float_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdErrSetCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_err_set_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToFloat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_to_float(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_float_to_int(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdErrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_err_to_int_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_int_to_err_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdBoolToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_bool_to_int(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdVectorType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *vector_type = ir_build_vector_type(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, vector_type, lval, result_loc); - } - case BuiltinFnIdShuffle: - { - // Used for the type expr and the mask expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, comptime_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, comptime_scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *shuffle_vector = ir_build_shuffle_vector(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, shuffle_vector, lval, result_loc); - } - case BuiltinFnIdSelect: - { - // Used for the type expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, comptime_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *select = ir_build_select(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, select, lval, result_loc); - } - case BuiltinFnIdSplat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *splat = ir_build_splat_src(ag, scope, node, - arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, splat, lval, result_loc); - } - case BuiltinFnIdMaximum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMax, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdMemcpy: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *ir_memcpy = ir_build_memcpy_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, ir_memcpy, lval, result_loc); - } - case BuiltinFnIdMemset: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc); - } - case BuiltinFnIdMinimum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMin, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdWasmMemorySize: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *ir_wasm_memory_size = ir_build_wasm_memory_size_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, ir_wasm_memory_size, lval, result_loc); - } - case BuiltinFnIdWasmMemoryGrow: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ir_wasm_memory_grow = ir_build_wasm_memory_grow_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, ir_wasm_memory_grow, lval, result_loc); - } - case BuiltinFnIdField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node_extra(ag, arg0_node, scope, LValPtr, nullptr); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ptr_instruction = ir_build_field_ptr_instruction(ag, scope, node, - arg0_value, arg1_value, false); - - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case BuiltinFnIdHasField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *type_info = ir_build_has_field(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, type_info, lval, result_loc); - } - case BuiltinFnIdTypeInfo: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *type_info = ir_build_type_info(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, type_info, lval, result_loc); - } - case BuiltinFnIdType: - { - AstNode *arg_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg = astgen_node(ag, arg_node, scope); - if (arg == ag->codegen->invalid_inst_src) - return arg; - - Stage1ZirInst *type = ir_build_type(ag, scope, node, arg); - return ir_lval_wrap(ag, scope, type, lval, result_loc); - } - case BuiltinFnIdBreakpoint: - return ir_lval_wrap(ag, scope, ir_build_breakpoint(ag, scope, node), lval, result_loc); - case BuiltinFnIdReturnAddress: - return ir_lval_wrap(ag, scope, ir_build_return_address_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameAddress: - return ir_lval_wrap(ag, scope, ir_build_frame_address_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameHandle: - if (ag->fn == nullptr) { - add_node_error(ag->codegen, node, - buf_sprintf("@frame() called outside of function definition")); - return ag->codegen->invalid_inst_src; - } - return ir_lval_wrap(ag, scope, ir_build_handle_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameType: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *frame_type = ir_build_frame_type(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, frame_type, lval, result_loc); - } - case BuiltinFnIdFrameSize: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *frame_size = ir_build_frame_size_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, frame_size, lval, result_loc); - } - case BuiltinFnIdAlignOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *align_of = ir_build_align_of(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, align_of, lval, result_loc); - } - case BuiltinFnIdAddWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpAdd), lval, result_loc); - case BuiltinFnIdSubWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpSub), lval, result_loc); - case BuiltinFnIdMulWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpMul), lval, result_loc); - case BuiltinFnIdShlWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpShl), lval, result_loc); - case BuiltinFnIdMulAdd: - return ir_lval_wrap(ag, scope, astgen_mul_add(ag, scope, node), lval, result_loc); - case BuiltinFnIdTypeName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *type_name = ir_build_type_name(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, type_name, lval, result_loc); - } - case BuiltinFnIdPanic: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *panic = ir_build_panic_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, panic, lval, result_loc); - } - case BuiltinFnIdPtrCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ptr_cast = ir_build_ptr_cast_src(ag, scope, node, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, ptr_cast, lval, result_loc); - } - case BuiltinFnIdBitCast: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *dest_type = astgen_node(ag, dest_type_node, scope); - if (dest_type == ag->codegen->invalid_inst_src) - return dest_type; - - ResultLocBitCast *result_loc_bit_cast = heap::c_allocator.create(); - result_loc_bit_cast->base.id = ResultLocIdBitCast; - result_loc_bit_cast->base.source_instruction = dest_type; - result_loc_bit_cast->base.allow_write_through_const = result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, ag->current_basic_block); - result_loc_bit_cast->parent = result_loc; - - ir_build_reset_result(ag, scope, node, &result_loc_bit_cast->base); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node_extra(ag, arg1_node, scope, LValNone, - &result_loc_bit_cast->base); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bitcast = ir_build_bit_cast_src(ag, scope, arg1_node, arg1_value, result_loc_bit_cast); - return ir_lval_wrap(ag, scope, bitcast, lval, result_loc); - } - case BuiltinFnIdAs: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *dest_type = astgen_node(ag, dest_type_node, scope); - if (dest_type == ag->codegen->invalid_inst_src) - return dest_type; - - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, dest_type, result_loc); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node_extra(ag, arg1_node, scope, LValNone, - &result_loc_cast->base); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_implicit_cast(ag, scope, node, arg1_value, result_loc_cast); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *int_to_ptr = ir_build_int_to_ptr_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, int_to_ptr, lval, result_loc); - } - case BuiltinFnIdPtrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *ptr_to_int = ir_build_ptr_to_int_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, ptr_to_int, lval, result_loc); - } - case BuiltinFnIdTagName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *tag_name = ir_build_tag_name_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, tag_name, lval, result_loc); - } - case BuiltinFnIdFieldParentPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *field_parent_ptr = ir_build_field_parent_ptr_src(ag, scope, node, - arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, field_parent_ptr, lval, result_loc); - } - case BuiltinFnIdOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *offset_of = ir_build_offset_of(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdBitOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *offset_of = ir_build_bit_offset_of(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdCall: { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "CallOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *options_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *options_inner = astgen_node_extra(ag, options_node, scope, - LValNone, &result_loc_cast->base); - if (options_inner == ag->codegen->invalid_inst_src) - return options_inner; - Stage1ZirInst *options = ir_build_implicit_cast(ag, scope, options_node, options_inner, result_loc_cast); - - AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1); - AstNode *args_node = node->data.fn_call_expr.params.at(2); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - return astgen_fn_call_with_args(ag, scope, node, - fn_ref_node, CallModifierNone, options, - args_node->data.container_init_expr.entries.items, - args_node->data.container_init_expr.entries.length, - lval, result_loc); - } else { - exec_add_error_node(ag->codegen, ag->exec, args_node, - buf_sprintf("TODO: @call with anon struct literal")); - return ag->codegen->invalid_inst_src; - } - } else { - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - Stage1ZirInst *args = astgen_node(ag, args_node, scope); - if (args == ag->codegen->invalid_inst_src) - return args; - - Stage1ZirInst *call = ir_build_call_extra(ag, scope, node, options, fn_ref, args, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); - } - } - case BuiltinFnIdAsyncCall: - return astgen_async_call(ag, scope, nullptr, node, lval, result_loc); - case BuiltinFnIdShlExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdShrExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSetEvalBranchQuota: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_eval_branch_quota = ir_build_set_eval_branch_quota(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_eval_branch_quota, lval, result_loc); - } - case BuiltinFnIdAlignCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *align_cast = ir_build_align_cast_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, align_cast, lval, result_loc); - } - case BuiltinFnIdThis: - { - Stage1ZirInst *this_inst = astgen_this(ag, scope, node); - return ir_lval_wrap(ag, scope, this_inst, lval, result_loc); - } - case BuiltinFnIdSetAlignStack: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_align_stack = ir_build_set_align_stack(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_align_stack, lval, result_loc); - } - case BuiltinFnIdExport: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "ExportOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *target_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *target_value = astgen_node(ag, target_node, scope); - if (target_value == ag->codegen->invalid_inst_src) - return target_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_export = ir_build_export(ag, scope, node, target_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_export, lval, result_loc); - } - case BuiltinFnIdExtern: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "ExternOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return type_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_extern = ir_build_extern(ag, scope, node, type_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc); - } - case BuiltinFnIdErrorReturnTrace: - { - Stage1ZirInst *error_return_trace = ir_build_error_return_trace_src(ag, scope, node, - IrInstErrorReturnTraceNull); - return ir_lval_wrap(ag, scope, error_return_trace, lval, result_loc); - } - case BuiltinFnIdAtomicRmw: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - Stage1ZirInst *arg4_value = astgen_node(ag, arg4_node, scope); - if (arg4_value == ag->codegen->invalid_inst_src) - return arg4_value; - - Stage1ZirInst *inst = ir_build_atomic_rmw_src(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value, arg4_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicLoad: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *inst = ir_build_atomic_load_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicStore: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *inst = ir_build_atomic_store_src(ag, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdIntToEnum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_to_enum_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdEnumToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_enum_to_int(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdCtz: - case BuiltinFnIdPopCount: - case BuiltinFnIdClz: - case BuiltinFnIdBswap: - case BuiltinFnIdBitReverse: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *arg1_value = arg0_value; - arg0_value = ir_build_typeof_1(ag, scope, arg0_node, arg1_value); - - Stage1ZirInst *result; - switch (builtin_fn->id) { - case BuiltinFnIdCtz: - result = ir_build_ctz(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdPopCount: - result = ir_build_pop_count(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdClz: - result = ir_build_clz(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBswap: - result = ir_build_bswap(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBitReverse: - result = ir_build_bit_reverse(ag, scope, node, arg0_value, arg1_value); - break; - default: - zig_unreachable(); - } - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdHasDecl: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *has_decl = ir_build_has_decl(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, has_decl, lval, result_loc); - } - case BuiltinFnIdUnionInit: - { - AstNode *union_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *union_type_inst = astgen_node(ag, union_type_node, scope); - if (union_type_inst == ag->codegen->invalid_inst_src) - return union_type_inst; - - AstNode *name_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *name_inst = astgen_node(ag, name_node, scope); - if (name_inst == ag->codegen->invalid_inst_src) - return name_inst; - - AstNode *init_node = node->data.fn_call_expr.params.at(2); - - return astgen_union_init_expr(ag, scope, node, union_type_inst, name_inst, init_node, - lval, result_loc); - } - case BuiltinFnIdSrc: - { - Stage1ZirInst *src_inst = ir_build_src(ag, scope, node); - return ir_lval_wrap(ag, scope, src_inst, lval, result_loc); - } - case BuiltinFnIdPrefetch: - { - ZigType *options_type = get_builtin_type(ag->codegen, "PrefetchOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *ptr_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *ptr_value = astgen_node(ag, ptr_node, scope); - if (ptr_value == ag->codegen->invalid_inst_src) - return ptr_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc); - } - case BuiltinFnIdAddrSpaceCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode* arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *addrspace_cast = ir_build_addrspace_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, addrspace_cast, lval, result_loc); - } - } - zig_unreachable(); -} - -static ScopeNoSuspend *get_scope_nosuspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdNoSuspend) - return (ScopeNoSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static Stage1ZirInst *astgen_fn_call(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) - return astgen_builtin_fn_call(ag, scope, node, lval, result_loc); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - CallModifier modifier = node->data.fn_call_expr.modifier; - if (is_nosuspend && modifier != CallModifierAsync) { - modifier = CallModifierNoSuspend; - } - - AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - return astgen_fn_call_with_args(ag, scope, node, fn_ref_node, modifier, - nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); -} - -static Stage1ZirInst *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfBoolExpr); - - Stage1ZirInst *condition = astgen_node(ag, node->data.if_bool_expr.condition, scope); - if (condition == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, condition); - } - - AstNode *then_node = node->data.if_bool_expr.then_block; - AstNode *else_node = node->data.if_bool_expr.else_node; - - Stage1ZirBasicBlock *then_block = ir_create_basic_block(ag, scope, "Then"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "Else"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "EndIf"); - - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, condition, - then_block, else_block, is_comptime); - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, then_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, subexpr_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - Stage1ZirInst *else_expr_result; - if (else_node) { - else_expr_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static Stage1ZirInst *astgen_prefix_op_id_lval(Stage1AstGen *ag, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - Stage1ZirInst *value = astgen_node_extra(ag, expr_node, scope, lval, nullptr); - if (value == ag->codegen->invalid_inst_src) - return value; - - return ir_build_un_op(ag, scope, node, op_id, value); -} - -static Stage1ZirInst *astgen_prefix_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrUnOp op_id) { - return astgen_prefix_op_id_lval(ag, scope, node, op_id, LValNone); -} - -static Stage1ZirInst *ir_expr_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *inst, ResultLoc *result_loc) { - if (inst == ag->codegen->invalid_inst_src) return inst; - ir_build_end_expr(ag, scope, inst->source_node, inst, result_loc); - return inst; -} - -static Stage1ZirInst *ir_lval_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *value, LVal lval, - ResultLoc *result_loc) -{ - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (value == ag->codegen->invalid_inst_src || - instr_is_unreachable(value) || - value->source_node->type == NodeTypeDefer || - value->id == Stage1ZirInstIdDeclVar) - { - return value; - } - - assert(lval != LValAssign); - if (lval == LValPtr) { - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a pointer of it. - return ir_build_ref_src(ag, scope, value->source_node, value); - } else if (result_loc != nullptr) { - return ir_expr_wrap(ag, scope, value, result_loc); - } else { - return value; - } - -} - -static PtrLen star_token_to_ptr_len(TokenId token_id) { - switch (token_id) { - case TokenIdStar: - case TokenIdStarStar: - return PtrLenSingle; - case TokenIdLBracket: - return PtrLenUnknown; - case TokenIdIdentifier: - return PtrLenC; - default: - zig_unreachable(); - } -} - -static Error token_number_literal_u32(Stage1AstGen *ag, AstNode *source_node, - RootStruct *root_struct, uint32_t *result, TokenIndex token) -{ - BigInt bigint; - token_number_literal_bigint(root_struct, &bigint, token); - - if (!bigint_fits_in_bits(&bigint, 32, false)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &bigint, 10); - exec_add_error_node(ag->codegen, ag->exec, source_node, - buf_sprintf("value %s too large for u32", buf_ptr(val_buf))); - bigint_deinit(&bigint); - return ErrorSemanticAnalyzeFail; - } - *result = bigint_as_u32(&bigint); - bigint_deinit(&bigint); - return ErrorNone; - -} - -static Stage1ZirInst *astgen_pointer_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypePointerType); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - TokenId star_tok_id = root_struct->token_ids[node->data.pointer_type.star_token]; - PtrLen ptr_len = star_token_to_ptr_len(star_tok_id); - - bool is_const = node->data.pointer_type.is_const; - bool is_volatile = node->data.pointer_type.is_volatile; - bool is_allow_zero = node->data.pointer_type.allow_zero_token != 0; - AstNode *sentinel_expr = node->data.pointer_type.sentinel; - AstNode *expr_node = node->data.pointer_type.op_expr; - AstNode *align_expr = node->data.pointer_type.align_expr; - - Stage1ZirInst *sentinel; - if (sentinel_expr != nullptr) { - sentinel = astgen_node(ag, sentinel_expr, scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - Stage1ZirInst *align_value; - if (align_expr != nullptr) { - align_value = astgen_node(ag, align_expr, scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - Stage1ZirInst *child_type = astgen_node(ag, expr_node, scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - uint32_t bit_offset_start = 0; - if (node->data.pointer_type.bit_offset_start != 0) { - if ((err = token_number_literal_u32(ag, node, root_struct, &bit_offset_start, - node->data.pointer_type.bit_offset_start))) - { - return ag->codegen->invalid_inst_src; - } - } - - uint32_t host_int_bytes = 0; - if (node->data.pointer_type.host_int_bytes != 0) { - if ((err = token_number_literal_u32(ag, node, root_struct, &host_int_bytes, - node->data.pointer_type.host_int_bytes))) - { - return ag->codegen->invalid_inst_src; - } - } - - if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { - exec_add_error_node(ag->codegen, ag->exec, node, - buf_sprintf("bit offset starts after end of host integer")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_ptr_type(ag, scope, node, child_type, is_const, is_volatile, - ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero); -} - -static Stage1ZirInst *astgen_catch_unreachable(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - AstNode *expr_node, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, scope, source_node, err_union_ptr, true, false); - if (payload_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (lval == LValPtr) - return payload_ptr; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, source_node, payload_ptr); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); -} - -static Stage1ZirInst *astgen_bool_not(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - Stage1ZirInst *value = astgen_node(ag, expr_node, scope); - if (value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_bool_not(ag, scope, node, value); -} - -static Stage1ZirInst *astgen_prefix_op_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypePrefixOpExpr); - - PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; - - switch (prefix_op) { - case PrefixOpInvalid: - zig_unreachable(); - case PrefixOpBoolNot: - return ir_lval_wrap(ag, scope, astgen_bool_not(ag, scope, node), lval, result_loc); - case PrefixOpBinNot: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpBinNot), lval, result_loc); - case PrefixOpNegation: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpNegation), lval, result_loc); - case PrefixOpNegationWrap: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpNegationWrap), lval, result_loc); - case PrefixOpOptional: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpOptional), lval, result_loc); - case PrefixOpAddrOf: { - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(ag, scope, astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr), lval, result_loc); - } - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_union_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc) -{ - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, source_node, parent_result_loc, union_type); - Stage1ZirInst *field_ptr = ir_build_field_ptr_instruction(ag, scope, source_node, container_ptr, - field_name, true); - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - ir_ref_instruction(field_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - Stage1ZirInst *init_union = ir_build_union_init_named_field(ag, scope, source_node, union_type, - field_name, field_ptr, container_ptr); - - return ir_lval_wrap(ag, scope, init_union, lval, parent_result_loc); -} - -static Stage1ZirInst *astgen_container_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *parent_result_loc) -{ - assert(node->type == NodeTypeContainerInitExpr); - - AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; - ContainerInitKind kind = container_init_expr->kind; - - ResultLocCast *result_loc_cast = nullptr; - ResultLoc *child_result_loc; - AstNode *init_array_type_source_node; - if (container_init_expr->type != nullptr) { - Stage1ZirInst *container_type; - if (container_init_expr->type->type == NodeTypeInferredArrayType) { - if (kind == ContainerInitKindStruct) { - add_node_error(ag->codegen, container_init_expr->type, - buf_sprintf("initializing array with struct syntax")); - return ag->codegen->invalid_inst_src; - } - Stage1ZirInst *sentinel; - if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) { - sentinel = astgen_node(ag, container_init_expr->type->data.inferred_array_type.sentinel, scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - Stage1ZirInst *elem_type = astgen_node(ag, - container_init_expr->type->data.inferred_array_type.child_type, scope); - if (elem_type == ag->codegen->invalid_inst_src) - return elem_type; - size_t item_count = container_init_expr->entries.length; - Stage1ZirInst *item_count_inst = ir_build_const_usize(ag, scope, node, item_count); - container_type = ir_build_array_type(ag, scope, node, item_count_inst, sentinel, elem_type); - } else { - container_type = astgen_node(ag, container_init_expr->type, scope); - if (container_type == ag->codegen->invalid_inst_src) - return container_type; - } - - result_loc_cast = ir_build_cast_result_loc(ag, container_type, parent_result_loc); - child_result_loc = &result_loc_cast->base; - init_array_type_source_node = container_type->source_node; - } else { - child_result_loc = parent_result_loc; - if (parent_result_loc->source_instruction != nullptr) { - init_array_type_source_node = parent_result_loc->source_instruction->source_node; - } else { - init_array_type_source_node = node; - } - } - - switch (kind) { - case ContainerInitKindStruct: { - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, node, child_result_loc, - nullptr); - - size_t field_count = container_init_expr->entries.length; - Stage1ZirInstContainerInitFieldsField *fields = heap::c_allocator.allocate(field_count); - for (size_t i = 0; i < field_count; i += 1) { - AstNode *entry_node = container_init_expr->entries.at(i); - assert(entry_node->type == NodeTypeStructValueField); - - Buf *name = entry_node->data.struct_val_field.name; - AstNode *expr_node = entry_node->data.struct_val_field.expr; - - Stage1ZirInst *field_ptr = ir_build_field_ptr(ag, scope, entry_node, container_ptr, name, true); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(field_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - fields[i].name = name; - fields[i].source_node = entry_node; - fields[i].result_loc = field_ptr; - } - Stage1ZirInst *result = ir_build_container_init_fields(ag, scope, node, field_count, - fields, container_ptr); - - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(ag, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(ag, scope, result, lval, parent_result_loc); - } - case ContainerInitKindArray: { - size_t item_count = container_init_expr->entries.length; - - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, node, child_result_loc, - nullptr); - - Stage1ZirInst **result_locs = heap::c_allocator.allocate(item_count); - for (size_t i = 0; i < item_count; i += 1) { - AstNode *expr_node = container_init_expr->entries.at(i); - - Stage1ZirInst *elem_index = ir_build_const_usize(ag, scope, expr_node, i); - Stage1ZirInst *elem_ptr = ir_build_elem_ptr(ag, scope, expr_node, container_ptr, - elem_index, false, PtrLenSingle, init_array_type_source_node); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = elem_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(elem_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - result_locs[i] = elem_ptr; - } - Stage1ZirInst *result = ir_build_container_init_list(ag, scope, node, item_count, - result_locs, container_ptr, init_array_type_source_node); - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(ag, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(ag, scope, result, lval, parent_result_loc); - } - } - zig_unreachable(); -} - -static ResultLocVar *ir_build_var_result_loc(Stage1AstGen *ag, Stage1ZirInst *alloca, ZigVar *var) { - ResultLocVar *result_loc_var = heap::c_allocator.create(); - result_loc_var->base.id = ResultLocIdVar; - result_loc_var->base.source_instruction = alloca; - result_loc_var->base.allow_write_through_const = true; - result_loc_var->var = var; - - ir_build_reset_result(ag, alloca->scope, alloca->source_node, &result_loc_var->base); - - return result_loc_var; -} - -static ResultLocCast *ir_build_cast_result_loc(Stage1AstGen *ag, Stage1ZirInst *dest_type, - ResultLoc *parent_result_loc) -{ - ResultLocCast *result_loc_cast = heap::c_allocator.create(); - result_loc_cast->base.id = ResultLocIdCast; - result_loc_cast->base.source_instruction = dest_type; - result_loc_cast->base.allow_write_through_const = parent_result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, ag->current_basic_block); - result_loc_cast->parent = parent_result_loc; - - ir_build_reset_result(ag, dest_type->scope, dest_type->source_node, &result_loc_cast->base); - - return result_loc_cast; -} - -static void build_decl_var_and_init(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var, - Stage1ZirInst *init, const char *name_hint, Stage1ZirInst *is_comptime) -{ - Stage1ZirInst *alloca = ir_build_alloca_src(ag, scope, source_node, nullptr, name_hint, is_comptime); - ResultLocVar *var_result_loc = ir_build_var_result_loc(ag, alloca, var); - ir_build_end_expr(ag, scope, source_node, init, &var_result_loc->base); - ir_build_var_decl_src(ag, scope, source_node, var, nullptr, alloca); -} - -static Stage1ZirInst *astgen_var_decl(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeVariableDeclaration); - - AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; - - if (buf_eql_str(variable_declaration->symbol, "_")) { - add_node_error(ag->codegen, node, buf_sprintf("`_` is not a declarable symbol")); - return ag->codegen->invalid_inst_src; - } - - // Used for the type expr and the align expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - Stage1ZirInst *type_instruction; - if (variable_declaration->type != nullptr) { - type_instruction = astgen_node(ag, variable_declaration->type, comptime_scope); - if (type_instruction == ag->codegen->invalid_inst_src) - return type_instruction; - } else { - type_instruction = nullptr; - } - - bool is_shadowable = false; - bool is_const = variable_declaration->is_const; - bool is_extern = variable_declaration->is_extern; - - bool is_comptime_scalar = ir_should_inline(ag->exec, scope) || variable_declaration->is_comptime; - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, scope, node, is_comptime_scalar); - ZigVar *var = ir_create_var(ag, node, scope, variable_declaration->symbol, - is_const, is_const, is_shadowable, is_comptime); - // we detect Stage1ZirInstDeclVar in gen_block to make sure the next node - // is inside var->child_scope - - if (!is_extern && !variable_declaration->expr) { - var->var_type = ag->codegen->builtin_types.entry_invalid; - add_node_error(ag->codegen, node, buf_sprintf("variables must be initialized")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *align_value = nullptr; - if (variable_declaration->align_expr != nullptr) { - align_value = astgen_node(ag, variable_declaration->align_expr, comptime_scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } - - if (variable_declaration->section_expr != nullptr) { - add_node_error(ag->codegen, variable_declaration->section_expr, - buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); - } - - // Parser should ensure that this never happens - assert(variable_declaration->threadlocal_tok == 0); - - Stage1ZirInst *alloca = ir_build_alloca_src(ag, scope, node, align_value, - buf_ptr(variable_declaration->symbol), is_comptime); - - // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = ir_build_var_result_loc(ag, alloca, var); - ResultLoc *init_result_loc; - ResultLocCast *result_loc_cast; - if (type_instruction != nullptr) { - result_loc_cast = ir_build_cast_result_loc(ag, type_instruction, &result_loc_var->base); - init_result_loc = &result_loc_cast->base; - } else { - result_loc_cast = nullptr; - init_result_loc = &result_loc_var->base; - } - - Scope *init_scope = is_comptime_scalar ? - create_comptime_scope(ag->codegen, variable_declaration->expr, scope) : scope; - - // Temporarily set the name of the Stage1Zir to the VariableDeclaration - // so that the struct or enum from the init expression inherits the name. - Buf *old_exec_name = ag->exec->name; - ag->exec->name = variable_declaration->symbol; - Stage1ZirInst *init_value = astgen_node_extra(ag, variable_declaration->expr, init_scope, - LValNone, init_result_loc); - ag->exec->name = old_exec_name; - - if (init_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (result_loc_cast != nullptr) { - Stage1ZirInst *implicit_cast = ir_build_implicit_cast(ag, scope, init_value->source_node, - init_value, result_loc_cast); - ir_build_end_expr(ag, scope, node, implicit_cast, &result_loc_var->base); - } - - return ir_build_var_decl_src(ag, scope, node, var, align_value, alloca); -} - -static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeWhileExpr); - - AstNode *continue_expr_node = node->data.while_expr.continue_expr; - AstNode *else_node = node->data.while_expr.else_node; - - Stage1ZirBasicBlock *cond_block = ir_create_basic_block(ag, scope, "WhileCond"); - Stage1ZirBasicBlock *body_block = ir_create_basic_block(ag, scope, "WhileBody"); - Stage1ZirBasicBlock *continue_block = continue_expr_node ? - ir_create_basic_block(ag, scope, "WhileContinue") : cond_block; - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, scope, "WhileEnd"); - Stage1ZirBasicBlock *else_block = else_node ? - ir_create_basic_block(ag, scope, "WhileElse") : end_block; - - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, scope, node, - ir_should_inline(ag->exec, scope) || node->data.while_expr.is_inline); - ir_build_br(ag, scope, node, cond_block, is_comptime); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Buf *var_symbol = node->data.while_expr.var_symbol; - Buf *err_symbol = node->data.while_expr.err_symbol; - if (err_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - - Scope *payload_scope; - AstNode *symbol_node = node; // TODO make more accurate - ZigVar *payload_var; - if (var_symbol) { - // TODO make it an error to write to payload variable - payload_var = ir_create_var(ag, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - payload_scope = payload_var->child_scope; - } else { - payload_scope = subexpr_scope; - } - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, payload_scope); - Stage1ZirInst *err_val_ptr = astgen_node_extra(ag, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (err_val_ptr == ag->codegen->invalid_inst_src) - return err_val_ptr; - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node->data.while_expr.condition, err_val_ptr, - true, false); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(is_err)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_err, - else_block, body_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - if (var_symbol) { - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, &spill_scope->base, symbol_node, - err_val_ptr, false, false); - Stage1ZirInst *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(ag, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, payload_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, payload_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result); - ir_build_br(ag, payload_scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, payload_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result); - ir_build_br(ag, payload_scope, node, cond_block, is_comptime); - } - } - - ir_set_cursor_at_end_and_append_block(ag, else_block); - assert(else_node != nullptr); - - // TODO make it an error to write to error variable - AstNode *err_symbol_node = else_node; // TODO make more accurate - ZigVar *err_var = ir_create_var(ag, err_symbol_node, scope, err_symbol, - true, false, false, is_comptime); - Scope *err_scope = err_var->child_scope; - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, err_scope, err_symbol_node, err_val_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, err_scope, err_symbol_node, err_ptr); - build_decl_var_and_init(ag, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - Stage1ZirInst *else_result = astgen_node_extra(ag, else_node, err_scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } else if (var_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - // TODO make it an error to write to payload variable - AstNode *symbol_node = node; // TODO make more accurate - - ZigVar *payload_var = ir_create_var(ag, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - Scope *child_scope = payload_var->child_scope; - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, child_scope); - Stage1ZirInst *maybe_val_ptr = astgen_node_extra(ag, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (maybe_val_ptr == ag->codegen->invalid_inst_src) - return maybe_val_ptr; - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, scope, node->data.while_expr.condition, maybe_val_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, scope, node->data.while_expr.condition, maybe_val); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(is_non_null)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_non_null, - body_block, else_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - Stage1ZirInst *payload_ptr = ir_build_optional_unwrap_ptr(ag, &spill_scope->base, symbol_node, maybe_val_ptr, false); - Stage1ZirInst *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(ag, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, child_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result); - ir_build_br(ag, child_scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, child_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result); - ir_build_br(ag, child_scope, node, cond_block, is_comptime); - } - } - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = astgen_node_extra(ag, else_node, scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } else { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Stage1ZirInst *cond_val = astgen_node(ag, node->data.while_expr.condition, scope); - if (cond_val == ag->codegen->invalid_inst_src) - return cond_val; - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(cond_val)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, cond_val, - body_block, else_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - ir_set_cursor_at_end_and_append_block(ag, body_block); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - - if (is_duplicate_label(ag->codegen, subexpr_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, subexpr_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result); - ir_build_br(ag, scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, subexpr_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result); - ir_build_br(ag, scope, node, cond_block, is_comptime); - } - } - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - - else_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } -} - -static Stage1ZirInst *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeForExpr); - - AstNode *array_node = node->data.for_expr.array_expr; - AstNode *elem_node = node->data.for_expr.elem_node; - AstNode *index_node = node->data.for_expr.index_node; - AstNode *body_node = node->data.for_expr.body; - AstNode *else_node = node->data.for_expr.else_node; - - if (!elem_node) { - add_node_error(ag->codegen, node, buf_sprintf("for loop expression missing element parameter")); - return ag->codegen->invalid_inst_src; - } - assert(elem_node->type == NodeTypeIdentifier); - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, parent_scope); - - Stage1ZirInst *array_val_ptr = astgen_node_extra(ag, array_node, &spill_scope->base, LValPtr, nullptr); - if (array_val_ptr == ag->codegen->invalid_inst_src) - return array_val_ptr; - - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, parent_scope, node, - ir_should_inline(ag->exec, parent_scope) || node->data.for_expr.is_inline); - - AstNode *index_var_source_node; - ZigVar *index_var; - const char *index_var_name; - if (index_node) { - index_var_source_node = index_node; - Buf *index_var_name_buf = node_identifier_buf(index_node); - index_var = ir_create_var(ag, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); - index_var_name = buf_ptr(index_var_name_buf); - } else { - index_var_source_node = node; - index_var = ir_create_var(ag, node, parent_scope, nullptr, true, false, true, is_comptime); - index_var_name = "i"; - } - - Stage1ZirInst *zero = ir_build_const_usize(ag, parent_scope, node, 0); - build_decl_var_and_init(ag, parent_scope, index_var_source_node, index_var, zero, index_var_name, is_comptime); - parent_scope = index_var->child_scope; - - Stage1ZirInst *one = ir_build_const_usize(ag, parent_scope, node, 1); - Stage1ZirInst *index_ptr = ir_build_var_ptr(ag, parent_scope, node, index_var); - - - Stage1ZirBasicBlock *cond_block = ir_create_basic_block(ag, parent_scope, "ForCond"); - Stage1ZirBasicBlock *body_block = ir_create_basic_block(ag, parent_scope, "ForBody"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "ForEnd"); - Stage1ZirBasicBlock *else_block = else_node ? ir_create_basic_block(ag, parent_scope, "ForElse") : end_block; - Stage1ZirBasicBlock *continue_block = ir_create_basic_block(ag, parent_scope, "ForContinue"); - - Buf *len_field_name = buf_create_from_str("len"); - Stage1ZirInst *len_ref = ir_build_field_ptr(ag, parent_scope, node, array_val_ptr, len_field_name, false); - Stage1ZirInst *len_val = ir_build_load_ptr(ag, &spill_scope->base, node, len_ref); - ir_build_br(ag, parent_scope, node, cond_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Stage1ZirInst *index_val = ir_build_load_ptr(ag, &spill_scope->base, node, index_ptr); - Stage1ZirInst *cond = ir_build_bin_op(ag, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_value = else_node ? nullptr : ir_build_const_void(ag, parent_scope, node); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, cond, - body_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - Stage1ZirInst *elem_ptr = ir_build_elem_ptr(ag, &spill_scope->base, node, array_val_ptr, index_val, - false, PtrLenSingle, nullptr); - // TODO make it an error to write to element variable or i variable. - Buf *elem_var_name = node_identifier_buf(elem_node); - ZigVar *elem_var = ir_create_var(ag, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); - Scope *child_scope = elem_var->child_scope; - - Stage1ZirInst *elem_value = node->data.for_expr.elem_is_ptr ? - elem_ptr : ir_build_load_ptr(ag, &spill_scope->base, elem_node, elem_ptr); - build_decl_var_and_init(ag, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); - - if (is_duplicate_label(ag->codegen, child_scope, node, node->data.for_expr.name)) - return ag->codegen->invalid_inst_src; - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = LValNone; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, body_node, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused for label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result); - ir_build_br(ag, child_scope, node, continue_block, is_comptime); - } - - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *new_index_val = ir_build_bin_op(ag, child_scope, node, IrBinOpAdd, index_val, one, false); - ir_build_store_ptr(ag, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true; - ir_build_br(ag, child_scope, node, cond_block, is_comptime); - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = astgen_node_extra(ag, else_node, parent_scope, LValNone, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_value); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static Stage1ZirInst *astgen_enum_literal(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeEnumLiteral); - // Currently, stage1 runs astgen for every comptime function call, - // resulting the allocation here wasting memory. As a workaround until - // the code is adjusted to make astgen run only once per source node, - // we memoize the result into the AST here. - if (node->data.enum_literal.name == nullptr) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - node->data.enum_literal.name = token_identifier_buf(root_struct, node->main_token + 1); - } - return ir_build_const_enum_literal(ag, scope, node, node->data.enum_literal.name); -} - -static Stage1ZirInst *astgen_string_literal(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeStringLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - - TokenId *token_ids = root_struct->token_ids; - - Buf *str = buf_alloc(); - if (token_ids[node->main_token] == TokenIdStringLiteral) { - size_t byte_offset = root_struct->token_locs[node->main_token].offset; - size_t bad_index; - if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { - add_token_error_offset(ag->codegen, node->owner, node->main_token, - buf_create_from_str("invalid string literal character"), bad_index); - } - src_assert(source[byte_offset] == '"', node); - byte_offset += 1; - } else if (token_ids[node->main_token] == TokenIdMultilineStringLiteralLine) { - TokenIndex tok_index = node->main_token; - bool first = true; - for (;token_ids[tok_index] == TokenIdMultilineStringLiteralLine; tok_index += 1) { - size_t byte_offset = root_struct->token_locs[tok_index].offset; - size_t end = byte_offset; - while (source[end] != 0 && source[end] != '\n') { - end += 1; - } - if (!first) { - buf_append_char(str, '\n'); - } else { - first = false; - } - buf_append_mem(str, source + byte_offset + 2, end - byte_offset - 2); - } - } else { - zig_unreachable(); - } - - return ir_build_const_str_lit(ag, scope, node, str); -} - -static Stage1ZirInst *astgen_array_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeArrayType); - - AstNode *size_node = node->data.array_type.size; - AstNode *child_type_node = node->data.array_type.child_type; - bool is_const = node->data.array_type.is_const; - bool is_volatile = node->data.array_type.is_volatile; - bool is_allow_zero = node->data.array_type.allow_zero_token != 0; - AstNode *sentinel_expr = node->data.array_type.sentinel; - AstNode *align_expr = node->data.array_type.align_expr; - - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - Stage1ZirInst *sentinel; - if (sentinel_expr != nullptr) { - sentinel = astgen_node(ag, sentinel_expr, comptime_scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - if (size_node) { - if (is_const) { - add_node_error(ag->codegen, node, buf_create_from_str("const qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (is_volatile) { - add_node_error(ag->codegen, node, buf_create_from_str("volatile qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (is_allow_zero) { - add_node_error(ag->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (align_expr != nullptr) { - add_node_error(ag->codegen, node, buf_create_from_str("align qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *size_value = astgen_node(ag, size_node, comptime_scope); - if (size_value == ag->codegen->invalid_inst_src) - return size_value; - - Stage1ZirInst *child_type = astgen_node(ag, child_type_node, comptime_scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - return ir_build_array_type(ag, scope, node, size_value, sentinel, child_type); - } else { - Stage1ZirInst *align_value; - if (align_expr != nullptr) { - align_value = astgen_node(ag, align_expr, comptime_scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - Stage1ZirInst *child_type = astgen_node(ag, child_type_node, comptime_scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - return ir_build_slice_type(ag, scope, node, child_type, is_const, is_volatile, sentinel, - align_value, is_allow_zero); - } -} - -static Stage1ZirInst *astgen_anyframe_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAnyFrameType); - - AstNode *payload_type_node = node->data.anyframe_type.payload_type; - Stage1ZirInst *payload_type_value = nullptr; - - if (payload_type_node != nullptr) { - payload_type_value = astgen_node(ag, payload_type_node, scope); - if (payload_type_value == ag->codegen->invalid_inst_src) - return payload_type_value; - - } - - return ir_build_anyframe_type(ag, scope, node, payload_type_value); -} - -static Stage1ZirInst *astgen_asm_expr(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &node->data.asm_expr; - - Stage1ZirInst *asm_template = astgen_node(ag, asm_expr->asm_template, scope); - if (asm_template == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - bool is_volatile = asm_expr->volatile_token != 0; - bool in_fn_scope = (scope_fn_entry(scope) != nullptr); - - if (!in_fn_scope) { - if (is_volatile) { - add_token_error(ag->codegen, node->owner, asm_expr->volatile_token, - buf_sprintf("volatile is meaningless on global assembly")); - return ag->codegen->invalid_inst_src; - } - - if (asm_expr->output_list.length != 0 || asm_expr->input_list.length != 0 || - asm_expr->clobber_list.length != 0) - { - add_node_error(ag->codegen, node, - buf_sprintf("global assembly cannot have inputs, outputs, or clobbers")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_asm_src(ag, scope, node, asm_template, nullptr, nullptr, - nullptr, 0, is_volatile, true); - } - - Stage1ZirInst **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); - Stage1ZirInst **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); - ZigVar **output_vars = heap::c_allocator.allocate(asm_expr->output_list.length); - size_t return_count = 0; - if (!is_volatile && asm_expr->output_list.length == 0) { - add_node_error(ag->codegen, node, - buf_sprintf("assembly expression with no output must be marked volatile")); - return ag->codegen->invalid_inst_src; - } - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (asm_output->return_type) { - return_count += 1; - - Stage1ZirInst *return_type = astgen_node(ag, asm_output->return_type, scope); - if (return_type == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - if (return_count > 1) { - add_node_error(ag->codegen, node, - buf_sprintf("inline assembly allows up to one output value")); - return ag->codegen->invalid_inst_src; - } - output_types[i] = return_type; - } else { - Buf *variable_name = asm_output->variable_name; - // TODO there is some duplication here with astgen_identifier. I need to do a full audit of how - // inline assembly works. https://github.com/ziglang/zig/issues/215 - ZigVar *var = find_variable(ag->codegen, scope, variable_name, nullptr); - if (var) { - output_vars[i] = var; - } else { - add_node_error(ag->codegen, node, - buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); - return ag->codegen->invalid_inst_src; - } - } - - const char modifier = *buf_ptr(asm_output->constraint); - if (modifier != '=') { - add_node_error(ag->codegen, node, - buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." - " Compiler TODO: see https://github.com/ziglang/zig/issues/215", - buf_ptr(asm_output->asm_symbolic_name), modifier)); - return ag->codegen->invalid_inst_src; - } - } - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - Stage1ZirInst *input_value = astgen_node(ag, asm_input->expr, scope); - if (input_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - input_list[i] = input_value; - } - - return ir_build_asm_src(ag, scope, node, asm_template, input_list, output_types, - output_vars, return_count, is_volatile, false); -} - -static Stage1ZirInst *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfOptional); - - Buf *var_symbol = node->data.test_expr.var_symbol; - AstNode *expr_node = node->data.test_expr.target_node; - AstNode *then_node = node->data.test_expr.then_node; - AstNode *else_node = node->data.test_expr.else_node; - bool var_is_ptr = node->data.test_expr.var_is_ptr; - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, expr_node, scope); - spill_scope->spill_harder = true; - - Stage1ZirInst *maybe_val_ptr = astgen_node_extra(ag, expr_node, &spill_scope->base, LValPtr, nullptr); - if (maybe_val_ptr == ag->codegen->invalid_inst_src) - return maybe_val_ptr; - - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, scope, node, maybe_val_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, scope, node, maybe_val); - - Stage1ZirBasicBlock *then_block = ir_create_basic_block(ag, scope, "OptionalThen"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "OptionalElse"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "OptionalEndIf"); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_non_null); - } - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, is_non_null, - then_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, then_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, &spill_scope->base, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - var_symbol, is_const, is_const, is_shadowable, is_comptime); - - Stage1ZirInst *payload_ptr = ir_build_optional_unwrap_ptr(ag, subexpr_scope, node, maybe_val_ptr, false); - Stage1ZirInst *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, node, payload_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return then_expr_result; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - Stage1ZirInst *else_expr_result; - if (else_node) { - else_expr_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static Stage1ZirInst *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfErrorExpr); - - AstNode *target_node = node->data.if_err_expr.target_node; - AstNode *then_node = node->data.if_err_expr.then_node; - AstNode *else_node = node->data.if_err_expr.else_node; - bool var_is_ptr = node->data.if_err_expr.var_is_ptr; - bool var_is_const = true; - Buf *var_symbol = node->data.if_err_expr.var_symbol; - Buf *err_symbol = node->data.if_err_expr.err_symbol; - - Stage1ZirInst *err_val_ptr = astgen_node_extra(ag, target_node, scope, LValPtr, nullptr); - if (err_val_ptr == ag->codegen->invalid_inst_src) - return err_val_ptr; - - Stage1ZirInst *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr); - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node, err_val_ptr, true, false); - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, scope, "TryOk"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "TryElse"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "TryEnd"); - - bool force_comptime = ir_should_inline(ag->exec, scope); - Stage1ZirInst *is_comptime = force_comptime ? ir_build_const_bool(ag, scope, node, true) : ir_build_test_comptime(ag, scope, node, is_err); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, is_err, else_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - Stage1ZirInst *var_is_comptime = force_comptime ? ir_build_const_bool(ag, subexpr_scope, node, true) : ir_build_test_comptime(ag, subexpr_scope, node, err_val); - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, subexpr_scope, node, err_val_ptr, false, false); - Stage1ZirInst *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, subexpr_scope, node, payload_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return then_expr_result; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - - Stage1ZirInst *else_expr_result; - if (else_node) { - Scope *err_var_scope; - if (err_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - err_symbol, is_const, is_const, is_shadowable, is_comptime); - - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, subexpr_scope, node, err_val_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, subexpr_scope, node, err_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime); - err_var_scope = var->child_scope; - } else { - err_var_scope = subexpr_scope; - } - else_expr_result = astgen_node_extra(ag, else_node, err_var_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static bool astgen_switch_prong_expr(Stage1AstGen *ag, Scope *scope, AstNode *switch_node, AstNode *prong_node, - Stage1ZirBasicBlock *end_block, Stage1ZirInst *is_comptime, Stage1ZirInst *var_is_comptime, - Stage1ZirInst *target_value_ptr, Stage1ZirInst **prong_values, size_t prong_values_len, - ZigList *incoming_blocks, ZigList *incoming_values, - Stage1ZirInstSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) -{ - assert(switch_node->type == NodeTypeSwitchExpr); - assert(prong_node->type == NodeTypeSwitchProng); - - if (prong_node->data.switch_prong.is_inline) { - exec_add_error_node(ag->codegen, ag->exec, prong_node, - buf_sprintf("inline switch cases not supported by stage1")); - return ag->codegen->invalid_inst_src; - } - - AstNode *expr_node = prong_node->data.switch_prong.expr; - AstNode *var_symbol_node = prong_node->data.switch_prong.var_symbol; - Scope *child_scope; - if (var_symbol_node) { - assert(var_symbol_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_symbol_node); - bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr; - - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, var_symbol_node, scope, - var_name, is_const, is_const, is_shadowable, var_is_comptime); - child_scope = var->child_scope; - Stage1ZirInst *var_value; - if (out_switch_else_var != nullptr) { - Stage1ZirInstSwitchElseVar *switch_else_var = ir_build_switch_else_var(ag, scope, var_symbol_node, - target_value_ptr); - *out_switch_else_var = switch_else_var; - Stage1ZirInst *payload_ptr = &switch_else_var->base; - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, payload_ptr); - } else if (prong_values != nullptr) { - Stage1ZirInst *payload_ptr = ir_build_switch_var(ag, scope, var_symbol_node, target_value_ptr, - prong_values, prong_values_len); - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, payload_ptr); - } else { - var_value = var_is_ptr ? - target_value_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, target_value_ptr); - } - build_decl_var_and_init(ag, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime); - } else { - child_scope = scope; - } - - Stage1ZirInst *expr_result = astgen_node_extra(ag, expr_node, child_scope, lval, result_loc); - if (expr_result == ag->codegen->invalid_inst_src) - return false; - if (!instr_is_unreachable(expr_result)) - ir_build_br(ag, scope, switch_node, end_block, is_comptime); - incoming_blocks->append(ag->current_basic_block); - incoming_values->append(expr_result); - return true; -} - -static Stage1ZirInst *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeSwitchExpr); - - AstNode *target_node = node->data.switch_expr.expr; - Stage1ZirInst *target_value_ptr = astgen_node_extra(ag, target_node, scope, LValPtr, nullptr); - if (target_value_ptr == ag->codegen->invalid_inst_src) - return target_value_ptr; - Stage1ZirInst *target_value = ir_build_switch_target(ag, scope, node, target_value_ptr); - - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "SwitchElse"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, scope, "SwitchEnd"); - - size_t prong_count = node->data.switch_expr.prongs.length; - ZigList cases = {0}; - - Stage1ZirInst *is_comptime; - Stage1ZirInst *var_is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - var_is_comptime = is_comptime; - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, target_value); - var_is_comptime = ir_build_test_comptime(ag, scope, node, target_value_ptr); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ZigList check_ranges = {0}; - - Stage1ZirInstSwitchElseVar *switch_else_var = nullptr; - - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = result_loc; - - ir_build_reset_result(ag, scope, node, &peer_parent->base); - - // First do the else and the ranges - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - AstNode *else_prong = nullptr; - AstNode *underscore_prong = nullptr; - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_node->data.switch_prong.any_items_are_range) { - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirInst *ok_bit = nullptr; - AstNode *last_item_node = nullptr; - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - last_item_node = item_node; - if (item_node->type == NodeTypeSwitchRange) { - AstNode *start_node = item_node->data.switch_range.start; - AstNode *end_node = item_node->data.switch_range.end; - - Stage1ZirInst *start_value = astgen_node(ag, start_node, comptime_scope); - if (start_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *end_value = astgen_node(ag, end_node, comptime_scope); - if (end_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = start_value; - check_range->end = end_value; - - Stage1ZirInst *lower_range_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpGreaterOrEq, - target_value, start_value, false); - Stage1ZirInst *upper_range_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpLessOrEq, - target_value, end_value, false); - Stage1ZirInst *both_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolAnd, - lower_range_ok, upper_range_ok, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolOr, both_ok, ok_bit, false); - } else { - ok_bit = both_ok; - } - } else { - Stage1ZirInst *item_value = astgen_node(ag, item_node, comptime_scope); - if (item_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - Stage1ZirInst *cmp_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpEq, - item_value, target_value, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolOr, cmp_ok, ok_bit, false); - } else { - ok_bit = cmp_ok; - } - } - } - - Stage1ZirBasicBlock *range_block_yes = ir_create_basic_block(ag, scope, "SwitchRangeYes"); - Stage1ZirBasicBlock *range_block_no = ir_create_basic_block(ag, scope, "SwitchRangeNo"); - - assert(ok_bit); - assert(last_item_node); - Stage1ZirInst *br_inst = ir_build_cond_br(ag, scope, last_item_node, ok_bit, - range_block_yes, range_block_no, is_comptime); - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_inst; - } - - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = range_block_yes; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, range_block_yes); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end_and_append_block(ag, range_block_no); - } else { - if (prong_item_count == 0) { - if (else_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("multiple else prongs in switch expression")); - add_error_note(ag->codegen, msg, else_prong, - buf_sprintf("previous else prong here")); - return ag->codegen->invalid_inst_src; - } - else_prong = prong_node; - } else if (prong_item_count == 1 && - prong_node->data.switch_prong.items.at(0)->type == NodeTypeIdentifier && - buf_eql_str(node_identifier_buf(prong_node->data.switch_prong.items.at(0)), "_")) { - if (underscore_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("multiple '_' prongs in switch expression")); - add_error_note(ag->codegen, msg, underscore_prong, - buf_sprintf("previous '_' prong here")); - return ag->codegen->invalid_inst_src; - } - underscore_prong = prong_node; - } else { - continue; - } - if (underscore_prong && else_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("else and '_' prong in switch expression")); - if (underscore_prong == prong_node) - add_error_note(ag->codegen, msg, else_prong, - buf_sprintf("else prong here")); - else - add_error_note(ag->codegen, msg, underscore_prong, - buf_sprintf("'_' prong here")); - return ag->codegen->invalid_inst_src; - } - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirBasicBlock *prev_block = ag->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = else_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, else_block); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, - &switch_else_var, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - ir_set_cursor_at_end(ag, prev_block); - } - } - - // next do the non-else non-ranges - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_item_count == 0) - continue; - if (prong_node->data.switch_prong.any_items_are_range) - continue; - if (underscore_prong == prong_node) - continue; - - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirBasicBlock *prong_block = ir_create_basic_block(ag, scope, "SwitchProng"); - Stage1ZirInst **items = heap::c_allocator.allocate(prong_item_count); - - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - assert(item_node->type != NodeTypeSwitchRange); - - Stage1ZirInst *item_value = astgen_node(ag, item_node, comptime_scope); - if (item_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - Stage1ZirInstSwitchBrCase *this_case = cases.add_one(); - this_case->value = item_value; - this_case->block = prong_block; - - items[item_i] = item_value; - } - - Stage1ZirBasicBlock *prev_block = ag->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = prong_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, prong_block); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end(ag, prev_block); - - } - - Stage1ZirInst *switch_prongs_void = ir_build_check_switch_prongs(ag, scope, node, target_value, - check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); - - Stage1ZirInst *br_instruction; - if (cases.length == 0) { - br_instruction = ir_build_br(ag, scope, node, else_block, is_comptime); - } else { - Stage1ZirInstSwitchBr *switch_br = ir_build_switch_br_src(ag, scope, node, target_value, else_block, - cases.length, cases.items, is_comptime, switch_prongs_void); - if (switch_else_var != nullptr) { - switch_else_var->switch_br = switch_br; - } - br_instruction = &switch_br->base; - } - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_instruction; - } - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction; - } - - if (!else_prong && !underscore_prong) { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ir_set_cursor_at_end_and_append_block(ag, else_block); - ir_build_unreachable(ag, scope, node); - } else { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - } - - ir_set_cursor_at_end_and_append_block(ag, end_block); - assert(incoming_blocks.length == incoming_values.length); - Stage1ZirInst *result_instruction; - if (incoming_blocks.length == 0) { - result_instruction = ir_build_const_void(ag, scope, node); - } else { - result_instruction = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - } - return ir_lval_wrap(ag, scope, result_instruction, lval, result_loc); -} - -static Stage1ZirInst *astgen_comptime(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeCompTime); - - Scope *child_scope = create_comptime_scope(ag->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return astgen_node_extra(ag, node->data.comptime_expr.expr, child_scope, lval, nullptr); -} - -static Stage1ZirInst *astgen_nosuspend(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeNoSuspend); - - Scope *child_scope = create_nosuspend_scope(ag->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return astgen_node_extra(ag, node->data.nosuspend_expr.expr, child_scope, lval, nullptr); -} - -static Stage1ZirInst *astgen_return_from_block(Stage1AstGen *ag, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, break_scope)) { - is_comptime = ir_build_const_bool(ag, break_scope, node, true); - } else { - is_comptime = block_scope->is_comptime; - } - - Stage1ZirInst *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent); - block_scope->peer_parent->peers.append(peer_result); - - result_value = astgen_node_extra(ag, node->data.break_expr.expr, break_scope, block_scope->lval, - &peer_result->base); - if (result_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(ag, break_scope, node); - } - - Stage1ZirBasicBlock *dest_block = block_scope->end_block; - if (!astgen_defers_for_block(ag, break_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - - block_scope->incoming_blocks->append(ag->current_basic_block); - block_scope->incoming_values->append(result_value); - return ir_build_br(ag, break_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_break(Stage1AstGen *ag, Scope *break_scope, AstNode *node) { - assert(node->type == NodeTypeBreak); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - // * (if it's a labeled break) labeled block => OK - - Scope *search_scope = break_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.break_expr.name != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name))); - return ag->codegen->invalid_inst_src; - } else { - add_node_error(ag->codegen, node, buf_sprintf("break expression outside loop")); - return ag->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(ag->codegen, node, buf_sprintf("cannot break out of defer expression")); - return ag->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.break_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdBlock) { - ScopeBlock *this_block_scope = (ScopeBlock *)search_scope; - if (node->data.break_expr.name != nullptr && - (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) - { - assert(this_block_scope->end_block != nullptr); - this_block_scope->name_used = true; - return astgen_return_from_block(ag, break_scope, node, this_block_scope); - } - } else if (search_scope->id == ScopeIdSuspend) { - add_node_error(ag->codegen, node, buf_sprintf("cannot break out of suspend block")); - return ag->codegen->invalid_inst_src; - } - search_scope = search_scope->parent; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, break_scope)) { - is_comptime = ir_build_const_bool(ag, break_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - Stage1ZirInst *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(loop_scope->peer_parent); - loop_scope->peer_parent->peers.append(peer_result); - - result_value = astgen_node_extra(ag, node->data.break_expr.expr, break_scope, - loop_scope->lval, &peer_result->base); - if (result_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(ag, break_scope, node); - } - - Stage1ZirBasicBlock *dest_block = loop_scope->break_block; - if (!astgen_defers_for_block(ag, break_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - - loop_scope->incoming_blocks->append(ag->current_basic_block); - loop_scope->incoming_values->append(result_value); - return ir_build_br(ag, break_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_continue(Stage1AstGen *ag, Scope *continue_scope, AstNode *node) { - assert(node->type == NodeTypeContinue); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - - ZigList runtime_scopes = {}; - - Scope *search_scope = continue_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.continue_expr.name != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); - return ag->codegen->invalid_inst_src; - } else { - add_node_error(ag->codegen, node, buf_sprintf("continue expression outside loop")); - return ag->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(ag->codegen, node, buf_sprintf("cannot continue out of defer expression")); - return ag->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.continue_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdRuntime) { - ScopeRuntime *scope_runtime = (ScopeRuntime *)search_scope; - runtime_scopes.append(scope_runtime); - } - search_scope = search_scope->parent; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, continue_scope)) { - is_comptime = ir_build_const_bool(ag, continue_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - for (size_t i = 0; i < runtime_scopes.length; i += 1) { - ScopeRuntime *scope_runtime = runtime_scopes.at(i); - ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime); - } - runtime_scopes.deinit(); - - Stage1ZirBasicBlock *dest_block = loop_scope->continue_block; - if (!astgen_defers_for_block(ag, continue_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - return ir_build_br(ag, continue_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_error_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeErrorType); - return ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_global_error_set); -} - -static Stage1ZirInst *astgen_defer(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeDefer); - - ScopeDefer *defer_child_scope = create_defer_scope(ag->codegen, node, parent_scope); - node->data.defer.child_scope = &defer_child_scope->base; - - ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(ag->codegen, node, parent_scope); - node->data.defer.expr_scope = &defer_expr_scope->base; - - return ir_build_const_void(ag, parent_scope, node); -} - -static Stage1ZirInst *astgen_slice(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeSliceExpr); - - AstNodeSliceExpr *slice_expr = &node->data.slice_expr; - AstNode *array_node = slice_expr->array_ref_expr; - AstNode *start_node = slice_expr->start; - AstNode *end_node = slice_expr->end; - AstNode *sentinel_node = slice_expr->sentinel; - - Stage1ZirInst *ptr_value = astgen_node_extra(ag, array_node, scope, LValPtr, nullptr); - if (ptr_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *start_value = astgen_node(ag, start_node, scope); - if (start_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *end_value; - if (end_node) { - end_value = astgen_node(ag, end_node, scope); - if (end_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - end_value = nullptr; - } - - Stage1ZirInst *sentinel_value; - if (sentinel_node) { - sentinel_value = astgen_node(ag, sentinel_node, scope); - if (sentinel_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - sentinel_value = nullptr; - } - - Stage1ZirInst *slice = ir_build_slice_src(ag, scope, node, ptr_value, start_value, end_value, - sentinel_value, true, result_loc); - return ir_lval_wrap(ag, scope, slice, lval, result_loc); -} - -static Stage1ZirInst *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeCatchExpr); - - AstNode *op1_node = node->data.unwrap_err_expr.op1; - AstNode *op2_node = node->data.unwrap_err_expr.op2; - AstNode *var_node = node->data.unwrap_err_expr.symbol; - - if (op2_node->type == NodeTypeUnreachable) { - if (var_node != nullptr) { - assert(var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_node); - add_node_error(ag->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return ag->codegen->invalid_inst_src; - } - return astgen_catch_unreachable(ag, parent_scope, node, op1_node, lval, result_loc); - } - - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, op1_node, parent_scope); - spill_scope->spill_harder = true; - - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, op1_node, &spill_scope->base, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *is_err = ir_build_test_err_src(ag, parent_scope, node, err_union_ptr, true, false); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, parent_scope)) { - is_comptime = ir_build_const_bool(ag, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, parent_scope, node, is_err); - } - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrOk"); - Stage1ZirBasicBlock *err_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrError"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrEnd"); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, is_err, err_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, ok_block, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, err_block); - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, &spill_scope->base, is_comptime); - Scope *err_scope; - if (var_node) { - assert(var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_node); - bool is_const = true; - bool is_shadowable = false; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, var_name, - is_const, is_const, is_shadowable, is_comptime); - err_scope = var->child_scope; - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, err_scope, node, err_union_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, err_scope, var_node, err_ptr); - build_decl_var_and_init(ag, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime); - } else { - err_scope = subexpr_scope; - } - Stage1ZirInst *err_result = astgen_node_extra(ag, op2_node, err_scope, LValNone, &peer_parent->peers.at(0)->base); - if (err_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_err_block = ag->current_basic_block; - if (!instr_is_unreachable(err_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - Stage1ZirInst *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, parent_scope, node, err_union_ptr, false, false); - Stage1ZirInst *unwrapped_payload = ir_build_load_ptr(ag, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(ag, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - Stage1ZirBasicBlock *after_ok_block = ag->current_basic_block; - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, end_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = err_result; - incoming_values[1] = unwrapped_payload; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_err_block; - incoming_blocks[1] = after_ok_block; - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) { - if (inner_scope == nullptr || inner_scope == outer_scope) return false; - bool need_comma = render_instance_name_recursive(codegen, name, outer_scope, inner_scope->parent); - if (inner_scope->id != ScopeIdVarDecl) - return need_comma; - - ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; - if (need_comma) - buf_append_char(name, ','); - // TODO: const ptr reinterpret here to make the var type agree with the value? - render_const_value(codegen, name, var_scope->var->const_value); - return true; -} - -Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc) -{ - // See https://ziglang.org/documentation/master/#Struct-Naming . - bool force_generic = false; - if (result_loc != nullptr - && result_loc->source_instruction != nullptr - && result_loc->source_instruction->source_node != nullptr - ) { - switch (result_loc->source_instruction->source_node->type) { - case NodeTypeVariableDeclaration: { - ZigType *import = get_scope_import(scope); - Buf *name = buf_alloc(); - append_namespace_qualification(codegen, name, import); - const auto &basename = result_loc->source_instruction->source_node->data.variable_declaration.symbol; - buf_append_buf(name, basename); - buf_init_from_buf(out_bare_name, basename); - return name; - } - case NodeTypeFnCallExpr: - case NodeTypeStructValueField: - force_generic = true; - break; - default: - break; - } - } - - if (!force_generic) { - if (exec != nullptr && exec->name != nullptr) { - buf_resize(out_bare_name, 0); - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = reinterpret_cast(scope); - append_namespace_qualification(codegen, out_bare_name, decls_scope->container_type); - } - buf_append_buf(out_bare_name, exec->name); - Buf *namespace_name = buf_alloc(); - buf_append_buf(namespace_name, out_bare_name); - return namespace_name; - } - if (exec != nullptr && exec->name_fn != nullptr) { - Buf *name = buf_alloc(); - buf_append_buf(name, &exec->name_fn->symbol_name); - buf_appendf(name, "("); - render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope); - buf_appendf(name, ")"); - buf_init_from_buf(out_bare_name, name); - return name; - } - } - - ZigType *import = get_scope_import(scope); - Buf *namespace_name = buf_alloc(); - append_namespace_qualification(codegen, namespace_name, import); - RootStruct *root_struct = source_node->owner->data.structure.root_struct; - TokenLoc tok_loc = root_struct->token_locs[source_node->main_token]; - buf_appendf(namespace_name, "%s:%u:%u", kind_name, - tok_loc.line + 1, tok_loc.column + 1); - buf_init_from_buf(out_bare_name, namespace_name); - return namespace_name; -} - -static Stage1ZirInst *astgen_container_decl(Stage1AstGen *ag, Scope *parent_scope, - AstNode *node, ResultLoc *result_loc) -{ - assert(node->type == NodeTypeContainerDecl); - - ContainerKind kind = node->data.container_decl.kind; - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ag->codegen, - ag->exec, container_string(kind), parent_scope, node, bare_name, result_loc); - - ContainerLayout layout = node->data.container_decl.layout; - ZigType *container_type = get_partial_container_type(ag->codegen, parent_scope, - kind, node, buf_ptr(name), bare_name, layout); - ScopeDecls *child_scope = get_container_scope(container_type); - - for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) { - AstNode *child_node = node->data.container_decl.decls.at(i); - scan_decls(ag->codegen, child_scope, child_node); - } - - TldContainer *tld_container = heap::c_allocator.create(); - init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope); - tld_container->type_entry = container_type; - tld_container->decls_scope = child_scope; - ag->codegen->resolve_queue.append(&tld_container->base); - - // Add this to the list to mark as invalid if analyzing this exec fails. - ag->exec->tld_list.append(&tld_container->base); - - return ir_build_const_type(ag, parent_scope, node, container_type); -} - -static Stage1ZirInst *astgen_err_set_decl(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeErrorSetDecl); - - uint32_t err_count = node->data.err_set_decl.decls.length; - - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", parent_scope, node, &bare_name, nullptr); - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_init_from_buf(&err_set_type->name, type_name); - err_set_type->data.error_set.err_count = err_count; - err_set_type->size_in_bits = ag->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ag->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ag->codegen->builtin_types.entry_global_error_set->abi_size; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(err_count); - - size_t errors_count = ag->codegen->errors_by_index.length + err_count; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - - for (uint32_t i = 0; i < err_count; i += 1) { - AstNode *field_node = node->data.err_set_decl.decls.at(i); - AstNode *symbol_node = ast_field_to_symbol_node(field_node); - Buf *err_name = node_identifier_buf(symbol_node); - ErrorTableEntry *err = heap::c_allocator.create(); - err->decl_node = field_node; - buf_init_from_buf(&err->name, err_name); - - auto existing_entry = ag->codegen->error_table.put_unique(err_name, err); - if (existing_entry) { - err->value = existing_entry->value->value; - } else { - size_t error_value_count = ag->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ag->codegen->err_tag_type->data.integral.bit_count)); - err->value = error_value_count; - ag->codegen->errors_by_index.append(err); - } - err_set_type->data.error_set.errors[i] = err; - - ErrorTableEntry *prev_err = errors[err->value]; - if (prev_err != nullptr) { - ErrorMsg *msg = add_node_error(ag->codegen, ast_field_to_symbol_node(err->decl_node), - buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); - add_error_note(ag->codegen, msg, ast_field_to_symbol_node(prev_err->decl_node), - buf_sprintf("other error here")); - return ag->codegen->invalid_inst_src; - } - errors[err->value] = err; - } - heap::c_allocator.deallocate(errors, errors_count); - return ir_build_const_type(ag, parent_scope, node, err_set_type); -} - -static Stage1ZirInst *astgen_fn_proto(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeFnProto); - - size_t param_count = node->data.fn_proto.params.length; - Stage1ZirInst **param_types = heap::c_allocator.allocate(param_count); - - bool is_var_args = false; - for (size_t i = 0; i < param_count; i += 1) { - AstNode *param_node = node->data.fn_proto.params.at(i); - if (param_node->data.param_decl.is_var_args) { - is_var_args = true; - break; - } - if (param_node->data.param_decl.anytype_token == 0) { - AstNode *type_node = param_node->data.param_decl.type; - Stage1ZirInst *type_value = astgen_node(ag, type_node, parent_scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - param_types[i] = type_value; - } else { - param_types[i] = nullptr; - } - } - - Stage1ZirInst *align_value = nullptr; - if (node->data.fn_proto.align_expr != nullptr) { - align_value = astgen_node(ag, node->data.fn_proto.align_expr, parent_scope); - if (align_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *callconv_value = nullptr; - if (node->data.fn_proto.callconv_expr != nullptr) { - callconv_value = astgen_node(ag, node->data.fn_proto.callconv_expr, parent_scope); - if (callconv_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *return_type; - if (node->data.fn_proto.return_type == nullptr) { - return_type = ir_build_const_type(ag, parent_scope, node, ag->codegen->builtin_types.entry_void); - } else { - return_type = astgen_node(ag, node->data.fn_proto.return_type, parent_scope); - if (return_type == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - return ir_build_fn_proto(ag, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args); -} - -static Stage1ZirInst *astgen_resume(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeResume); - - Stage1ZirInst *target_inst = astgen_node_extra(ag, node->data.resume_expr.expr, scope, LValPtr, nullptr); - if (target_inst == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_resume_src(ag, scope, node, target_inst); -} - -static Stage1ZirInst *astgen_await_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeAwaitExpr); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - - AstNode *expr_node = node->data.await_expr.expr; - if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - if (entry != nullptr) { - BuiltinFnEntry *builtin_fn = entry->value; - if (builtin_fn->id == BuiltinFnIdAsyncCall) { - return astgen_async_call(ag, scope, node, expr_node, lval, result_loc); - } - } - } - - if (!ag->fn) { - add_node_error(ag->codegen, node, buf_sprintf("await outside function definition")); - return ag->codegen->invalid_inst_src; - } - ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(ag->codegen, node, buf_sprintf("cannot await inside suspend block")); - add_error_note(ag->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here")); - existing_suspend_scope->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *target_inst = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (target_inst == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *await_inst = ir_build_await_src(ag, scope, node, target_inst, result_loc, is_nosuspend); - return ir_lval_wrap(ag, scope, await_inst, lval, result_loc); -} - -static Stage1ZirInst *astgen_suspend(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeSuspend); - - if (!ag->fn) { - add_node_error(ag->codegen, node, buf_sprintf("suspend outside function definition")); - return ag->codegen->invalid_inst_src; - } - if (get_scope_nosuspend(parent_scope) != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("suspend in nosuspend scope")); - return ag->codegen->invalid_inst_src; - } - - ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(ag->codegen, node, buf_sprintf("cannot suspend inside suspend block")); - add_error_note(ag->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here")); - existing_suspend_scope->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInstSuspendBegin *begin = ir_build_suspend_begin_src(ag, parent_scope, node); - ScopeSuspend *suspend_scope = create_suspend_scope(ag->codegen, node, parent_scope); - Scope *child_scope = &suspend_scope->base; - Stage1ZirInst *susp_res = astgen_node(ag, node->data.suspend.block, child_scope); - if (susp_res == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res); - - return ir_build_suspend_finish_src(ag, parent_scope, node, begin); -} - -static Stage1ZirInst *astgen_node_raw(Stage1AstGen *ag, AstNode *node, Scope *scope, - LVal lval, ResultLoc *result_loc) -{ - assert(scope); - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - case NodeTypeBlock: - return astgen_block(ag, scope, node, lval, result_loc); - case NodeTypeGroupedExpr: - return astgen_node_raw(ag, node->data.grouped_expr, scope, lval, result_loc); - case NodeTypeBinOpExpr: - return astgen_bin_op(ag, scope, node, lval, result_loc); - case NodeTypeIntLiteral: - return ir_lval_wrap(ag, scope, astgen_int_lit(ag, scope, node), lval, result_loc); - case NodeTypeFloatLiteral: - return ir_lval_wrap(ag, scope, astgen_float_lit(ag, scope, node), lval, result_loc); - case NodeTypeCharLiteral: - return ir_lval_wrap(ag, scope, astgen_char_lit(ag, scope, node), lval, result_loc); - case NodeTypeIdentifier: - return astgen_identifier(ag, scope, node, lval, result_loc); - case NodeTypeFnCallExpr: - return astgen_fn_call(ag, scope, node, lval, result_loc); - case NodeTypeIfBoolExpr: - return astgen_if_bool_expr(ag, scope, node, lval, result_loc); - case NodeTypePrefixOpExpr: - return astgen_prefix_op_expr(ag, scope, node, lval, result_loc); - case NodeTypeContainerInitExpr: - return astgen_container_init_expr(ag, scope, node, lval, result_loc); - case NodeTypeVariableDeclaration: - return astgen_var_decl(ag, scope, node); - case NodeTypeWhileExpr: - return astgen_while_expr(ag, scope, node, lval, result_loc); - case NodeTypeForExpr: - return astgen_for_expr(ag, scope, node, lval, result_loc); - case NodeTypeArrayAccessExpr: - return astgen_array_access(ag, scope, node, lval, result_loc); - case NodeTypeReturnExpr: - return astgen_return(ag, scope, node, lval, result_loc); - case NodeTypeFieldAccessExpr: - { - Stage1ZirInst *ptr_instruction = astgen_field_access(ag, scope, node); - if (ptr_instruction == ag->codegen->invalid_inst_src) - return ptr_instruction; - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case NodeTypePtrDeref: { - AstNode *expr_node = node->data.ptr_deref_expr.target; - - LVal child_lval = lval; - if (child_lval == LValAssign) - child_lval = LValPtr; - - Stage1ZirInst *value = astgen_node_extra(ag, expr_node, scope, child_lval, nullptr); - if (value == ag->codegen->invalid_inst_src) - return value; - - // We essentially just converted any lvalue from &(x.*) to (&x).*; - // this inhibits checking that x is a pointer later, so we directly - // record whether the pointer check is needed - Stage1ZirInst *un_op = ir_build_un_op_lval(ag, scope, node, IrUnOpDereference, value, lval, result_loc); - return ir_expr_wrap(ag, scope, un_op, result_loc); - } - case NodeTypeUnwrapOptional: { - AstNode *expr_node = node->data.unwrap_optional.expr; - - Stage1ZirInst *maybe_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (maybe_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, scope, node, maybe_ptr, true ); - if (lval == LValPtr || lval == LValAssign) - return unwrapped_ptr; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, unwrapped_ptr); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case NodeTypeArrayType: - return ir_lval_wrap(ag, scope, astgen_array_type(ag, scope, node), lval, result_loc); - case NodeTypePointerType: - return ir_lval_wrap(ag, scope, astgen_pointer_type(ag, scope, node), lval, result_loc); - case NodeTypeAnyFrameType: - return ir_lval_wrap(ag, scope, astgen_anyframe_type(ag, scope, node), lval, result_loc); - case NodeTypeStringLiteral: - return ir_lval_wrap(ag, scope, astgen_string_literal(ag, scope, node), lval, result_loc); - case NodeTypeAsmExpr: - return ir_lval_wrap(ag, scope, astgen_asm_expr(ag, scope, node), lval, result_loc); - case NodeTypeIfErrorExpr: - return astgen_if_err_expr(ag, scope, node, lval, result_loc); - case NodeTypeIfOptional: - return astgen_if_optional_expr(ag, scope, node, lval, result_loc); - case NodeTypeSwitchExpr: - return astgen_switch_expr(ag, scope, node, lval, result_loc); - case NodeTypeCompTime: - return ir_expr_wrap(ag, scope, astgen_comptime(ag, scope, node, lval), result_loc); - case NodeTypeNoSuspend: - return ir_expr_wrap(ag, scope, astgen_nosuspend(ag, scope, node, lval), result_loc); - case NodeTypeErrorType: - return ir_lval_wrap(ag, scope, astgen_error_type(ag, scope, node), lval, result_loc); - case NodeTypeBreak: - return ir_lval_wrap(ag, scope, astgen_break(ag, scope, node), lval, result_loc); - case NodeTypeContinue: - return ir_lval_wrap(ag, scope, astgen_continue(ag, scope, node), lval, result_loc); - case NodeTypeUnreachable: - return ir_build_unreachable(ag, scope, node); - case NodeTypeDefer: - return ir_lval_wrap(ag, scope, astgen_defer(ag, scope, node), lval, result_loc); - case NodeTypeSliceExpr: - return astgen_slice(ag, scope, node, lval, result_loc); - case NodeTypeCatchExpr: - return astgen_catch(ag, scope, node, lval, result_loc); - case NodeTypeContainerDecl: - return ir_lval_wrap(ag, scope, astgen_container_decl(ag, scope, node, result_loc), lval, result_loc); - case NodeTypeFnProto: - return ir_lval_wrap(ag, scope, astgen_fn_proto(ag, scope, node), lval, result_loc); - case NodeTypeErrorSetDecl: - return ir_lval_wrap(ag, scope, astgen_err_set_decl(ag, scope, node), lval, result_loc); - case NodeTypeResume: - return ir_lval_wrap(ag, scope, astgen_resume(ag, scope, node), lval, result_loc); - case NodeTypeAwaitExpr: - return astgen_await_expr(ag, scope, node, lval, result_loc); - case NodeTypeSuspend: - return ir_lval_wrap(ag, scope, astgen_suspend(ag, scope, node), lval, result_loc); - case NodeTypeEnumLiteral: - return ir_lval_wrap(ag, scope, astgen_enum_literal(ag, scope, node), lval, result_loc); - case NodeTypeInferredArrayType: - add_node_error(ag->codegen, node, - buf_sprintf("inferred array size invalid here")); - return ag->codegen->invalid_inst_src; - case NodeTypeAnyTypeField: - return ir_lval_wrap(ag, scope, - ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_anytype), lval, result_loc); - } - zig_unreachable(); -} - -ResultLoc *no_result_loc(void) { - ResultLocNone *result_loc_none = heap::c_allocator.create(); - result_loc_none->base.id = ResultLocIdNone; - return &result_loc_none->base; -} - -static Stage1ZirInst *astgen_node_extra(Stage1AstGen *ag, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc) -{ - if (lval == LValAssign) { - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - - // cannot be assigned to - case NodeTypeBlock: - case NodeTypeGroupedExpr: - case NodeTypeBinOpExpr: - case NodeTypeIntLiteral: - case NodeTypeFloatLiteral: - case NodeTypeCharLiteral: - case NodeTypeIfBoolExpr: - case NodeTypeContainerInitExpr: - case NodeTypeVariableDeclaration: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeReturnExpr: - case NodeTypeArrayType: - case NodeTypePointerType: - case NodeTypeAnyFrameType: - case NodeTypeStringLiteral: - case NodeTypeAsmExpr: - case NodeTypeIfErrorExpr: - case NodeTypeIfOptional: - case NodeTypeSwitchExpr: - case NodeTypeCompTime: - case NodeTypeNoSuspend: - case NodeTypeErrorType: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeUnreachable: - case NodeTypeDefer: - case NodeTypeSliceExpr: - case NodeTypeCatchExpr: - case NodeTypeContainerDecl: - case NodeTypeFnProto: - case NodeTypeErrorSetDecl: - case NodeTypeResume: - case NodeTypeAwaitExpr: - case NodeTypeSuspend: - case NodeTypeEnumLiteral: - case NodeTypeInferredArrayType: - case NodeTypeAnyTypeField: - case NodeTypePrefixOpExpr: - add_node_error(ag->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return ag->codegen->invalid_inst_src; - - // @field can be assigned to - case NodeTypeFnCallExpr: - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(ag->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return ag->codegen->invalid_inst_src; - } - - if (entry->value->id == BuiltinFnIdField) { - break; - } - } - add_node_error(ag->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return ag->codegen->invalid_inst_src; - - - // can be assigned to - case NodeTypeUnwrapOptional: - case NodeTypePtrDeref: - case NodeTypeFieldAccessExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeIdentifier: - break; - } - } - if (result_loc == nullptr) { - // Create a result location indicating there is none - but if one gets created - // it will be properly distributed. - result_loc = no_result_loc(); - ir_build_reset_result(ag, scope, node, result_loc); - } - Scope *child_scope; - if (ag->exec->is_inline || - (ag->fn != nullptr && ag->fn->child_scope == scope)) - { - child_scope = scope; - } else { - child_scope = &create_expr_scope(ag->codegen, node, scope)->base; - } - Stage1ZirInst *result = astgen_node_raw(ag, node, child_scope, lval, result_loc); - if (result == ag->codegen->invalid_inst_src) { - if (ag->exec->first_err_trace_msg == nullptr) { - ag->exec->first_err_trace_msg = ag->codegen->trace_err; - } - } - return result; -} - -static Stage1ZirInst *astgen_node(Stage1AstGen *ag, AstNode *node, Scope *scope) { - return astgen_node_extra(ag, node, scope, LValNone, nullptr); -} - -bool stage1_astgen(CodeGen *codegen, AstNode *node, Scope *scope, Stage1Zir *stage1_zir, - ZigFn *fn, bool in_c_import_scope) -{ - assert(node->owner); - - Stage1AstGen ir_builder = {0}; - Stage1AstGen *ag = &ir_builder; - - ag->codegen = codegen; - ag->fn = fn; - ag->in_c_import_scope = in_c_import_scope; - ag->exec = stage1_zir; - ag->main_block_node = node; - - Stage1ZirBasicBlock *entry_block = ir_create_basic_block(ag, scope, "Entry"); - ir_set_cursor_at_end_and_append_block(ag, entry_block); - // Entry block gets a reference because we enter it to begin. - ir_ref_bb(ag->current_basic_block); - - Stage1ZirInst *result = astgen_node_extra(ag, node, scope, LValNone, nullptr); - - if (result == ag->codegen->invalid_inst_src) - return false; - - if (ag->exec->first_err_trace_msg != nullptr) { - codegen->trace_err = ag->exec->first_err_trace_msg; - return false; - } - - if (!instr_is_unreachable(result)) { - ir_build_add_implicit_return_type(ag, scope, result->source_node, result, nullptr); - // no need for save_err_ret_addr because this cannot return error - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base); - ir_build_return_src(ag, scope, result->source_node, result); - } - - return true; -} - -bool stage1_astgen_fn(CodeGen *codegen, ZigFn *fn) { - assert(fn != nullptr); - assert(fn->child_scope != nullptr); - return stage1_astgen(codegen, fn->body_node, fn->child_scope, fn->stage1_zir, fn, false); -} - -void invalidate_exec(Stage1Zir *exec, ErrorMsg *msg) { - if (exec->first_err_trace_msg != nullptr) - return; - - exec->first_err_trace_msg = msg; - - for (size_t i = 0; i < exec->tld_list.length; i += 1) { - exec->tld_list.items[i]->resolution = TldResolutionInvalid; - } -} - -AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node) { - if (err_set_field_node->type == NodeTypeIdentifier) { - return err_set_field_node; - } else if (err_set_field_node->type == NodeTypeErrorSetField) { - assert(err_set_field_node->data.err_set_field.field_name->type == NodeTypeIdentifier); - return err_set_field_node->data.err_set_field.field_name; - } else { - return err_set_field_node; - } -} - -void ir_add_call_stack_errors_gen(CodeGen *codegen, Stage1Air *exec, ErrorMsg *err_msg, int limit) { - if (!exec || !exec->source_node || limit < 0) return; - add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); - - ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); -} - -void Stage1ZirInst::src() { - Stage1ZirInst *inst = this; - if (inst->source_node != nullptr) { - inst->source_node->src(); - } else { - fprintf(stderr, "(null source node)\n"); - } -} - diff --git a/src/stage1/astgen.hpp b/src/stage1/astgen.hpp deleted file mode 100644 index c0ca583f56ef..000000000000 --- a/src/stage1/astgen.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ASTGEN_HPP -#define ZIG_ASTGEN_HPP - -#include "all_types.hpp" - -bool stage1_astgen(CodeGen *g, AstNode *node, Scope *scope, Stage1Zir *stage1_zir, - ZigFn *fn, bool in_c_import_scope); -bool stage1_astgen_fn(CodeGen *g, ZigFn *fn_entry); - -bool ir_inst_src_has_side_effects(Stage1ZirInst *inst); - -ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime, - bool skip_name_check); - -ResultLoc *no_result_loc(void); - -void invalidate_exec(Stage1Zir *exec, ErrorMsg *msg); - -AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node); -void ir_add_call_stack_errors_gen(CodeGen *codegen, Stage1Air *exec, ErrorMsg *err_msg, - int limit); - -void destroy_instruction_src(Stage1ZirInst *inst); - -bool ir_should_inline(Stage1Zir *exec, Scope *scope); -Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc); - -#endif diff --git a/src/stage1/bigfloat.cpp b/src/stage1/bigfloat.cpp deleted file mode 100644 index e5f21e34ea11..000000000000 --- a/src/stage1/bigfloat.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "bigfloat.hpp" -#include "bigint.hpp" -#include "buffer.hpp" -#include "softfloat.hpp" -#include "softfloat_ext.hpp" -#include "parse_f128.h" -#include -#include -#include - - -void bigfloat_init_128(BigFloat *dest, float128_t x) { - dest->value = x; -} - -void bigfloat_init_16(BigFloat *dest, float16_t x) { - f16_to_f128M(x, &dest->value); -} - -void bigfloat_init_32(BigFloat *dest, float x) { - float32_t f32_val; - memcpy(&f32_val, &x, sizeof(float)); - f32_to_f128M(f32_val, &dest->value); -} - -void bigfloat_init_64(BigFloat *dest, double x) { - float64_t f64_val; - memcpy(&f64_val, &x, sizeof(double)); - f64_to_f128M(f64_val, &dest->value); -} - -void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { - memcpy(&dest->value, &x->value, sizeof(float128_t)); -} - -void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { - ui32_to_f128M(0, &dest->value); - if (op->digit_count == 0) - return; - - float128_t base; - ui64_to_f128M(UINT64_MAX, &base); - float128_t one_f128; - ui32_to_f128M(1, &one_f128); - f128M_add(&base, &one_f128, &base); - - const uint64_t *digits = bigint_ptr(op); - - for (size_t i = op->digit_count - 1;;) { - float128_t digit_f128; - ui64_to_f128M(digits[i], &digit_f128); - - f128M_mulAdd(&dest->value, &base, &digit_f128, &dest->value); - - if (i == 0) { - if (op->is_negative) { - f128M_neg(&dest->value, &dest->value); - } - return; - } - i -= 1; - } -} - -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr) { - char *str_begin = (char *)buf_ptr; - char *str_end; - - errno = 0; - dest->value = parse_f128(str_begin, &str_end); - if (errno) { - return ErrorOverflow; - } - - return ErrorNone; -} - -void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_add(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_negate(BigFloat *dest, const BigFloat *op) { - f128M_neg(&op->value, &dest->value); -} - -void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_sub(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_mul(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); - f128M_roundToInt(&dest->value, softfloat_round_minMag, false, &dest->value); -} - -void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); - f128M_roundToInt(&dest->value, softfloat_round_min, false, &dest->value); -} - -void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_rem(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_rem(&op1->value, &op2->value, &dest->value); - f128M_add(&dest->value, &op2->value, &dest->value); - f128M_rem(&dest->value, &op2->value, &dest->value); -} - -void bigfloat_append_buf(Buf *buf, const BigFloat *op) { - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - - // TODO actually print f128 - float64_t f64_value = f128M_to_f64(&op->value); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); -} - -Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { - if (f128M_lt(&op1->value, &op2->value)) { - return CmpLT; - } else if (f128M_eq(&op1->value, &op2->value)) { - return CmpEQ; - } else { - return CmpGT; - } -} - -float16_t bigfloat_to_f16(const BigFloat *bigfloat) { - return f128M_to_f16(&bigfloat->value); -} - -float bigfloat_to_f32(const BigFloat *bigfloat) { - float32_t f32_value = f128M_to_f32(&bigfloat->value); - float result; - memcpy(&result, &f32_value, sizeof(float)); - return result; -} - -double bigfloat_to_f64(const BigFloat *bigfloat) { - float64_t f64_value = f128M_to_f64(&bigfloat->value); - double result; - memcpy(&result, &f64_value, sizeof(double)); - return result; -} - -float128_t bigfloat_to_f128(const BigFloat *bigfloat) { - return bigfloat->value; -} - -Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(&bigfloat->value, &zero_float)) { - return CmpLT; - } else if (f128M_eq(&bigfloat->value, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } -} - -bool bigfloat_has_fraction(const BigFloat *bigfloat) { - float128_t floored; - f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored); - return !f128M_eq(&floored, &bigfloat->value); -} - -void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { - f128M_sqrt(&op->value, &dest->value); -} - -void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - if (bigfloat_is_nan(op1)) { - bigfloat_init_bigfloat(dest, op2); - } else if (bigfloat_is_nan(op2)) { - bigfloat_init_bigfloat(dest, op1); - } else if (f128M_lt(&op1->value, &op2->value)) { - bigfloat_init_bigfloat(dest, op1); - } else { - bigfloat_init_bigfloat(dest, op2); - } -} - -void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - if (bigfloat_is_nan(op1)) { - bigfloat_init_bigfloat(dest, op2); - } else if (bigfloat_is_nan(op2)) { - bigfloat_init_bigfloat(dest, op1); - } else if (f128M_lt(&op1->value, &op2->value)) { - bigfloat_init_bigfloat(dest, op2); - } else { - bigfloat_init_bigfloat(dest, op1); - } -} - -bool bigfloat_is_nan(const BigFloat *op) { - return f128M_isSignalingNaN(&op->value); -} diff --git a/src/stage1/bigfloat.hpp b/src/stage1/bigfloat.hpp deleted file mode 100644 index ffaff320e995..000000000000 --- a/src/stage1/bigfloat.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BIGFLOAT_HPP -#define ZIG_BIGFLOAT_HPP - -#include "bigint.hpp" -#include "error.hpp" -#include -#include - -#include "softfloat_types.h" - - -struct BigFloat { - float128_t value; -}; - -struct Buf; - -void bigfloat_init_16(BigFloat *dest, float16_t x); -void bigfloat_init_32(BigFloat *dest, float x); -void bigfloat_init_64(BigFloat *dest, double x); -void bigfloat_init_128(BigFloat *dest, float128_t x); -void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x); -void bigfloat_init_bigint(BigFloat *dest, const BigInt *op); -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr); - -float16_t bigfloat_to_f16(const BigFloat *bigfloat); -float bigfloat_to_f32(const BigFloat *bigfloat); -double bigfloat_to_f64(const BigFloat *bigfloat); -float128_t bigfloat_to_f128(const BigFloat *bigfloat); - -void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_negate(BigFloat *dest, const BigFloat *op); -void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); -void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_append_buf(Buf *buf, const BigFloat *op); -Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); - - -bool bigfloat_is_nan(const BigFloat *op); - -// convenience functions -Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); -bool bigfloat_has_fraction(const BigFloat *bigfloat); - -#endif diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp deleted file mode 100644 index 3180095be647..000000000000 --- a/src/stage1/bigint.cpp +++ /dev/null @@ -1,1895 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "bigfloat.hpp" -#include "bigint.hpp" -#include "buffer.hpp" -#include "list.hpp" -#include "os.hpp" -#include "softfloat.hpp" - -#include -#include - -static uint64_t bigint_as_unsigned(const BigInt *bigint); - -static void bigint_normalize(BigInt *dest) { - const uint64_t *digits = bigint_ptr(dest); - - size_t last_nonzero_digit = SIZE_MAX; - for (size_t i = 0; i < dest->digit_count; i += 1) { - uint64_t digit = digits[i]; - if (digit != 0) { - last_nonzero_digit = i; - } - } - if (last_nonzero_digit == SIZE_MAX) { - dest->is_negative = false; - dest->digit_count = 0; - } else { - dest->digit_count = last_nonzero_digit + 1; - if (last_nonzero_digit == 0) { - dest->data.digit = digits[0]; - } - } -} - -static uint8_t digit_to_char(uint8_t digit, bool uppercase) { - if (digit <= 9) { - return digit + '0'; - } else if (digit <= 35) { - return (digit - 10) + (uppercase ? 'A' : 'a'); - } else { - zig_unreachable(); - } -} - -size_t bigint_bits_needed(const BigInt *op) { - size_t full_bits = op->digit_count * 64; - size_t leading_zero_count = bigint_clz(op, full_bits); - size_t bits_needed = full_bits - leading_zero_count; - return bits_needed + op->is_negative; -} - -static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) { - if (bit_count == 0 || op->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - BigInt pos_op = {0}; - - if (op->is_negative) { - BigInt negated = {0}; - bigint_negate(&negated, op); - - BigInt inverted = {0}; - bigint_not(&inverted, &negated, bit_count, false); - - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - bigint_add(&pos_op, &inverted, &one); - } else { - bigint_init_bigint(&pos_op, op); - } - - dest->is_negative = false; - const uint64_t *op_digits = bigint_ptr(&pos_op); - if (pos_op.digit_count == 1) { - dest->data.digit = op_digits[0]; - if (bit_count < 64) { - dest->data.digit &= (1ULL << bit_count) - 1; - } - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - size_t digits_to_copy = bit_count / 64; - size_t leftover_bits = bit_count % 64; - dest->digit_count = digits_to_copy + ((leftover_bits == 0) ? 0 : 1); - if (dest->digit_count == 1) { - dest->data.digit = op_digits[0]; - if (leftover_bits != 0) { - dest->data.digit &= (1ULL << leftover_bits) - 1; - } - if (dest->data.digit == 0) dest->digit_count = 0; - return; - } - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - for (size_t i = 0; i < digits_to_copy; i += 1) { - uint64_t digit = (i < pos_op.digit_count) ? op_digits[i] : 0; - dest->data.digits[i] = digit; - } - if (leftover_bits != 0) { - uint64_t digit = (digits_to_copy < pos_op.digit_count) ? op_digits[digits_to_copy] : 0; - dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1); - } - bigint_normalize(dest); -} - -static bool bit_at_index(const BigInt *bi, size_t index) { - size_t digit_index = index / 64; - if (digit_index >= bi->digit_count) - return false; - size_t digit_bit_index = index % 64; - const uint64_t *digits = bigint_ptr(bi); - uint64_t digit = digits[digit_index]; - return ((digit >> digit_bit_index) & 0x1) == 0x1; -} - -static void from_twos_complement(BigInt *dest, const BigInt *src, size_t bit_count, bool is_signed) { - assert(!src->is_negative); - - if (bit_count == 0 || src->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (is_signed && bit_at_index(src, bit_count - 1)) { - BigInt negative_one = {0}; - bigint_init_signed(&negative_one, -1); - - BigInt minus_one = {0}; - bigint_add(&minus_one, src, &negative_one); - - BigInt inverted = {0}; - bigint_not(&inverted, &minus_one, bit_count, false); - - bigint_negate(dest, &inverted); - return; - - } - - bigint_init_bigint(dest, src); -} - -void bigint_init_unsigned(BigInt *dest, uint64_t x) { - if (x == 0) { - dest->digit_count = 0; - dest->is_negative = false; - return; - } - dest->digit_count = 1; - dest->data.digit = x; - dest->is_negative = false; -} - -void bigint_init_signed(BigInt *dest, int64_t x) { - if (x >= 0) { - return bigint_init_unsigned(dest, x); - } - dest->is_negative = true; - dest->digit_count = 1; - dest->data.digit = ((uint64_t)(-(x + 1))) + 1; -} - -void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative) { - if (digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } else if (digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = digits[0]; - dest->is_negative = is_negative; - bigint_normalize(dest); - return; - } - - dest->digit_count = digit_count; - dest->is_negative = is_negative; - dest->data.digits = heap::c_allocator.allocate_nonzero(digit_count); - memcpy(dest->data.digits, digits, sizeof(uint64_t) * digit_count); - - bigint_normalize(dest); -} - -void bigint_init_bigint(BigInt *dest, const BigInt *src) { - if (src->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } else if (src->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = src->data.digit; - dest->is_negative = src->is_negative; - return; - } - dest->is_negative = src->is_negative; - dest->digit_count = src->digit_count; - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - memcpy(dest->data.digits, src->data.digits, sizeof(uint64_t) * dest->digit_count); -} - -void bigint_deinit(BigInt *bi) { - if (bi->digit_count > 1) - heap::c_allocator.deallocate(bi->data.digits, bi->digit_count); -} - -void bigint_init_bigfloat(BigInt *dest, const BigFloat *op) { - float128_t zero; - ui32_to_f128M(0, &zero); - - dest->is_negative = f128M_lt(&op->value, &zero); - float128_t abs_val; - if (dest->is_negative) { - f128M_sub(&zero, &op->value, &abs_val); - } else { - memcpy(&abs_val, &op->value, sizeof(float128_t)); - } - - float128_t max_u64; - ui64_to_f128M(UINT64_MAX, &max_u64); - if (f128M_le(&abs_val, &max_u64)) { - dest->digit_count = 1; - dest->data.digit = f128M_to_ui64(&abs_val, softfloat_round_minMag, false); - bigint_normalize(dest); - return; - } - - float128_t amt; - f128M_div(&abs_val, &max_u64, &amt); - float128_t remainder; - f128M_rem(&abs_val, &max_u64, &remainder); - - dest->digit_count = 2; - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - dest->data.digits[0] = f128M_to_ui64(&remainder, softfloat_round_minMag, false); - dest->data.digits[1] = f128M_to_ui64(&amt, softfloat_round_minMag, false); - bigint_normalize(dest); -} - -bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed) { - assert(bn->digit_count != 1 || bn->data.digit != 0); - if (bit_count == 0) { - return bigint_cmp_zero(bn) == CmpEQ; - } - if (bn->digit_count == 0) { - return true; - } - - if (!is_signed) { - if(bn->is_negative) return false; - size_t full_bits = bn->digit_count * 64; - size_t leading_zero_count = bigint_clz(bn, full_bits); - return bit_count >= full_bits - leading_zero_count; - } - - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - BigInt shl_amt = {0}; - bigint_init_unsigned(&shl_amt, bit_count - 1); - - BigInt max_value_plus_one = {0}; - bigint_shl(&max_value_plus_one, &one, &shl_amt); - - BigInt max_value = {0}; - bigint_sub(&max_value, &max_value_plus_one, &one); - - BigInt min_value = {0}; - bigint_negate(&min_value, &max_value_plus_one); - - Cmp min_cmp = bigint_cmp(bn, &min_value); - Cmp max_cmp = bigint_cmp(bn, &max_value); - - return (min_cmp == CmpGT || min_cmp == CmpEQ) && (max_cmp == CmpLT || max_cmp == CmpEQ); -} - -void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian) { - if (bit_count == 0) - return; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, big_int, bit_count); - - const uint64_t *twos_comp_digits = bigint_ptr(&twos_comp); - - size_t bits_in_last_digit = bit_count % 64; - if (bits_in_last_digit == 0) bits_in_last_digit = 64; - size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; - size_t unwritten_byte_count = 8 - bytes_in_last_digit; - - if (is_big_endian) { - size_t last_digit_index = (bit_count - 1) / 64; - size_t digit_index = last_digit_index; - size_t buf_index = 0; - for (;;) { - uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; - - for (size_t byte_index = 7;;) { - uint8_t byte = x & 0xff; - if (digit_index == last_digit_index) { - buf[buf_index + byte_index - unwritten_byte_count] = byte; - if (byte_index == unwritten_byte_count) break; - } else { - buf[buf_index + byte_index] = byte; - } - - if (byte_index == 0) break; - byte_index -= 1; - x >>= 8; - } - - if (digit_index == 0) break; - if (digit_index == last_digit_index) { - buf_index += bytes_in_last_digit; - } else { - buf_index += 8; - } - digit_index -= 1; - } - } else { - size_t digit_count = (bit_count + 63) / 64; - size_t buf_index = 0; - for (size_t digit_index = 0; digit_index < digit_count; digit_index += 1) { - uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; - - for (size_t byte_index = 0; - byte_index < 8 && (digit_index + 1 < digit_count || byte_index < bytes_in_last_digit); - byte_index += 1) - { - uint8_t byte = x & 0xff; - buf[buf_index] = byte; - buf_index += 1; - x >>= 8; - } - } - } -} - - -void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, - bool is_signed) -{ - if (bit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - dest->digit_count = (bit_count + 63) / 64; - uint64_t *digits; - if (dest->digit_count == 1) { - digits = &dest->data.digit; - } else { - digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - dest->data.digits = digits; - } - - size_t bits_in_last_digit = bit_count % 64; - if (bits_in_last_digit == 0) { - bits_in_last_digit = 64; - } - size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; - size_t unread_byte_count = 8 - bytes_in_last_digit; - - if (is_big_endian) { - size_t buf_index = 0; - uint64_t digit = 0; - for (size_t byte_index = unread_byte_count; byte_index < 8; byte_index += 1) { - uint8_t byte = buf[buf_index]; - buf_index += 1; - digit <<= 8; - digit |= byte; - } - digits[dest->digit_count - 1] = digit; - for (size_t digit_index = 1; digit_index < dest->digit_count; digit_index += 1) { - digit = 0; - for (size_t byte_index = 0; byte_index < 8; byte_index += 1) { - uint8_t byte = buf[buf_index]; - buf_index += 1; - digit <<= 8; - digit |= byte; - } - digits[dest->digit_count - 1 - digit_index] = digit; - } - } else { - size_t buf_index = 0; - for (size_t digit_index = 0; digit_index < dest->digit_count; digit_index += 1) { - uint64_t digit = 0; - size_t end_byte_index = (digit_index == dest->digit_count - 1) ? bytes_in_last_digit : 8; - for (size_t byte_index = 0; byte_index < end_byte_index; byte_index += 1) { - uint64_t byte = buf[buf_index]; - buf_index += 1; - - digit |= byte << (8 * byte_index); - } - digits[digit_index] = digit; - } - } - - if (is_signed) { - bigint_normalize(dest); - BigInt tmp = {0}; - bigint_init_bigint(&tmp, dest); - from_twos_complement(dest, &tmp, bit_count, true); - } else { - dest->is_negative = false; - bigint_normalize(dest); - } -} - -#if defined(_MSC_VER) -static bool add_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 + op2; - return *result < op1 || *result < op2; -} - -static bool sub_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 - op2; - return *result > op1; -} - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 * op2; - - if (op1 == 0 || op2 == 0) - return false; - - if (op1 > UINT64_MAX / op2) - return true; - - if (op2 > UINT64_MAX / op1) - return true; - - return false; -} -#else -static bool add_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_uaddll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} - -static bool sub_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_usubll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_umulll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} -#endif - -void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2) { - switch (bigint_cmp(op1, op2)) { - case CmpEQ: - case CmpLT: - return bigint_init_bigint(dest, op2); - case CmpGT: - return bigint_init_bigint(dest, op1); - } -} - -void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) { - switch (bigint_cmp(op1, op2)) { - case CmpEQ: - case CmpLT: - return bigint_init_bigint(dest, op1); - case CmpGT: - return bigint_init_bigint(dest, op2); - } -} - -/// clamps op within bit_count/signedness boundaries -/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1] -/// unsigned bounds are [0..2^bit_count-1] -void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) { - bool is_negative = dest->is_negative; - // unsigned and dest->is_negative => clamp to 0 - if (is_negative && !is_signed) { - bigint_deinit(dest); - bigint_init_unsigned(dest, 0); - return; - } - // compute the number of bits required to store the value, and use that - // to decide whether to clamp the result - // to workaround the fact this bits_needed calculation would yield 65 or more for - // all negative numbers, set is_negative to false. this is a cheap way to find - // bits_needed(abs(dest)). - dest->is_negative = false; - // because we've set is_negative to false, we have to account for the extra bit here - // by adding 1 additional bit_needed when (is_negative && !is_signed). - size_t full_bits = dest->digit_count * 64; - size_t leading_zero_count = bigint_clz(dest, full_bits); - size_t bits_needed = full_bits - leading_zero_count + (is_negative && !is_signed); - - bit_count -= is_signed; - if(bits_needed > bit_count) { - BigInt one; - bigint_init_unsigned(&one, 1); - BigInt bit_count_big; - bigint_init_unsigned(&bit_count_big, bit_count); - - if(is_signed) { - if(is_negative) { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - bigint_deinit(dest); - *dest = bound; - } else { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - BigInt bound_sub_one; - bigint_sub(&bound_sub_one, &bound, &one); - bigint_deinit(&bound); - bigint_deinit(dest); - *dest = bound_sub_one; - } - } else { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - BigInt bound_sub_one; - bigint_sub(&bound_sub_one, &bound, &one); - bigint_deinit(&bound); - bigint_deinit(dest); - *dest = bound_sub_one; - } - } - dest->is_negative = is_negative; -} - -void bigint_add_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_add(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_sub_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_sub(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_mul_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_mul(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_shl_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_shl(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative == op2->is_negative) { - dest->is_negative = op1->is_negative; - - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - bool overflow = add_u64_overflow(op1_digits[0], op2_digits[0], &dest->data.digit); - if (overflow == 0 && op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - size_t i = 1; - uint64_t first_digit = dest->data.digit; - dest->data.digits = heap::c_allocator.allocate_nonzero(max(op1->digit_count, op2->digit_count) + 1); - dest->data.digits[0] = first_digit; - - for (;;) { - bool found_digit = false; - uint64_t x = overflow; - overflow = 0; - - if (i < op1->digit_count) { - found_digit = true; - uint64_t digit = op1_digits[i]; - overflow += add_u64_overflow(x, digit, &x); - } - - if (i < op2->digit_count) { - found_digit = true; - uint64_t digit = op2_digits[i]; - overflow += add_u64_overflow(x, digit, &x); - } - - dest->data.digits[i] = x; - i += 1; - - if (!found_digit) { - dest->digit_count = i; - bigint_normalize(dest); - return; - } - } - } - const BigInt *op_pos; - const BigInt *op_neg; - if (op1->is_negative) { - op_neg = op1; - op_pos = op2; - } else { - op_pos = op1; - op_neg = op2; - } - - BigInt op_neg_abs = {0}; - bigint_negate(&op_neg_abs, op_neg); - const BigInt *bigger_op; - const BigInt *smaller_op; - switch (bigint_cmp(op_pos, &op_neg_abs)) { - case CmpEQ: - bigint_init_unsigned(dest, 0); - return; - case CmpLT: - bigger_op = &op_neg_abs; - smaller_op = op_pos; - dest->is_negative = true; - break; - case CmpGT: - bigger_op = op_pos; - smaller_op = &op_neg_abs; - dest->is_negative = false; - break; - } - const uint64_t *bigger_op_digits = bigint_ptr(bigger_op); - const uint64_t *smaller_op_digits = bigint_ptr(smaller_op); - uint64_t overflow = sub_u64_overflow(bigger_op_digits[0], smaller_op_digits[0], &dest->data.digit); - if (overflow == 0 && bigger_op->digit_count == 1 && smaller_op->digit_count == 1) { - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - uint64_t first_digit = dest->data.digit; - dest->data.digits = heap::c_allocator.allocate_nonzero(bigger_op->digit_count); - dest->data.digits[0] = first_digit; - size_t i = 1; - - for (;;) { - uint64_t x = bigger_op_digits[i]; - uint64_t prev_overflow = overflow; - overflow = 0; - - if (i < smaller_op->digit_count) { - uint64_t digit = smaller_op_digits[i]; - overflow += sub_u64_overflow(x, digit, &x); - } - - overflow += sub_u64_overflow(x, prev_overflow, &x); - dest->data.digits[i] = x; - i += 1; - - if (i >= bigger_op->digit_count) { - break; - } - } - assert(overflow == 0); - dest->digit_count = i; - bigint_normalize(dest); -} - -void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_add(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2) { - BigInt op2_negated = {0}; - bigint_negate(&op2_negated, op2); - return bigint_add(dest, op1, &op2_negated); -} - -void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt op2_negated = {0}; - bigint_negate(&op2_negated, op2); - return bigint_add_wrap(dest, op1, &op2_negated, bit_count, is_signed); -} - -static void mul_overflow(uint64_t op1, uint64_t op2, uint64_t *lo, uint64_t *hi) { - uint64_t u1 = (op1 & 0xffffffff); - uint64_t v1 = (op2 & 0xffffffff); - uint64_t t = (u1 * v1); - uint64_t w3 = (t & 0xffffffff); - uint64_t k = (t >> 32); - - op1 >>= 32; - t = (op1 * v1) + k; - k = (t & 0xffffffff); - uint64_t w1 = (t >> 32); - - op2 >>= 32; - t = (u1 * op2) + k; - k = (t >> 32); - - *hi = (op1 * op2) + w1 + k; - *lo = (t << 32) + w3; -} - -static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar) { - bigint_init_unsigned(dest, 0); - - BigInt bi_64; - bigint_init_unsigned(&bi_64, 64); - - const uint64_t *op_digits = bigint_ptr(op); - size_t i = op->digit_count - 1; - - for (;;) { - BigInt shifted; - bigint_shl(&shifted, dest, &bi_64); - - uint64_t result_scalar; - uint64_t carry_scalar; - mul_overflow(scalar, op_digits[i], &result_scalar, &carry_scalar); - - BigInt result; - bigint_init_unsigned(&result, result_scalar); - - BigInt carry; - bigint_init_unsigned(&carry, carry_scalar); - - BigInt carry_shifted; - bigint_shl(&carry_shifted, &carry, &bi_64); - - BigInt tmp; - bigint_add(&tmp, &shifted, &carry_shifted); - - bigint_add(dest, &tmp, &result); - - if (i == 0) { - break; - } - i -= 1; - } -} - -void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0 || op2->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - uint64_t carry; - mul_overflow(op1_digits[0], op2_digits[0], &dest->data.digit, &carry); - if (carry == 0 && op1->digit_count == 1 && op2->digit_count == 1) { - dest->is_negative = (op1->is_negative != op2->is_negative); - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - - bigint_init_unsigned(dest, 0); - - BigInt bi_64; - bigint_init_unsigned(&bi_64, 64); - - size_t i = op2->digit_count - 1; - for (;;) { - BigInt shifted; - bigint_shl(&shifted, dest, &bi_64); - - BigInt scalar_result; - mul_scalar(&scalar_result, op1, op2_digits[i]); - - bigint_add(dest, &scalar_result, &shifted); - - if (i == 0) { - break; - } - i -= 1; - } - - dest->is_negative = (op1->is_negative != op2->is_negative); - bigint_normalize(dest); -} - -void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_mul(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -enum ZeroBehavior { - /// \brief The returned value is undefined. - ZB_Undefined, - /// \brief The returned value is numeric_limits::max() - ZB_Max, - /// \brief The returned value is numeric_limits::digits - ZB_Width -}; - -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior) { - if (!Val) - return std::numeric_limits::digits; - - // Bisection method. - std::size_t ZeroBits = 0; - for (T Shift = std::numeric_limits::digits >> 1; Shift; Shift >>= 1) { - T Tmp = Val >> Shift; - if (Tmp) - Val = Tmp; - else - ZeroBits |= Shift; - } - return ZeroBits; - } -}; - -#if __GNUC__ >= 4 || defined(_MSC_VER) -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior ZB) { - if (ZB != ZB_Undefined && Val == 0) - return 32; - -#if defined(_MSC_VER) - unsigned long Index; - _BitScanReverse(&Index, Val); - return Index ^ 31; -#else - return __builtin_clz(Val); -#endif - } -}; - -#if !defined(_MSC_VER) || defined(_M_X64) -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior ZB) { - if (ZB != ZB_Undefined && Val == 0) - return 64; - -#if defined(_MSC_VER) - unsigned long Index; - _BitScanReverse64(&Index, Val); - return Index ^ 63; -#else - return __builtin_clzll(Val); -#endif - } -}; -#endif -#endif - -/// \brief Count number of 0's from the most significant bit to the least -/// stopping at the first 1. -/// -/// Only unsigned integral types are allowed. -/// -/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are -/// valid arguments. -template -std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { - static_assert(std::numeric_limits::is_integer && - !std::numeric_limits::is_signed, - "Only unsigned integral types are allowed."); - return LeadingZerosCounter::count(Val, ZB); -} - -/// Make a 64-bit integer from a high / low pair of 32-bit integers. -constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { - return ((uint64_t)High << 32) | (uint64_t)Low; -} - -/// Return the high 32 bits of a 64 bit value. -constexpr inline uint32_t Hi_32(uint64_t Value) { - return static_cast(Value >> 32); -} - -/// Return the low 32 bits of a 64 bit value. -constexpr inline uint32_t Lo_32(uint64_t Value) { - return static_cast(Value); -} - -/// Implementation of Knuth's Algorithm D (Division of nonnegative integers) -/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The -/// variables here have the same names as in the algorithm. Comments explain -/// the algorithm and any deviation from it. -static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, - unsigned m, unsigned n) -{ - assert(u && "Must provide dividend"); - assert(v && "Must provide divisor"); - assert(q && "Must provide quotient"); - assert(u != v && u != q && v != q && "Must use different memory"); - assert(n>1 && "n must be > 1"); - - // b denotes the base of the number system. In our case b is 2^32. - const uint64_t b = uint64_t(1) << 32; - - // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of - // u and v by d. Note that we have taken Knuth's advice here to use a power - // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of - // 2 allows us to shift instead of multiply and it is easy to determine the - // shift amount from the leading zeros. We are basically normalizing the u - // and v so that its high bits are shifted to the top of v's range without - // overflow. Note that this can require an extra word in u so that u must - // be of length m+n+1. - unsigned shift = countLeadingZeros(v[n-1]); - uint32_t v_carry = 0; - uint32_t u_carry = 0; - if (shift) { - for (unsigned i = 0; i < m+n; ++i) { - uint32_t u_tmp = u[i] >> (32 - shift); - u[i] = (u[i] << shift) | u_carry; - u_carry = u_tmp; - } - for (unsigned i = 0; i < n; ++i) { - uint32_t v_tmp = v[i] >> (32 - shift); - v[i] = (v[i] << shift) | v_carry; - v_carry = v_tmp; - } - } - u[m+n] = u_carry; - - // D2. [Initialize j.] Set j to m. This is the loop counter over the places. - int j = m; - do { - // D3. [Calculate q'.]. - // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q') - // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') - // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease - // qp by 1, increase rp by v[n-1], and repeat this test if rp < b. The test - // on v[n-2] determines at high speed most of the cases in which the trial - // value qp is one too large, and it eliminates all cases where qp is two - // too large. - uint64_t dividend = Make_64(u[j+n], u[j+n-1]); - uint64_t qp = dividend / v[n-1]; - uint64_t rp = dividend % v[n-1]; - if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) { - qp--; - rp += v[n-1]; - if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2])) - qp--; - } - - // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with - // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation - // consists of a simple multiplication by a one-place number, combined with - // a subtraction. - // The digits (u[j+n]...u[j]) should be kept positive; if the result of - // this step is actually negative, (u[j+n]...u[j]) should be left as the - // true value plus b**(n+1), namely as the b's complement of - // the true value, and a "borrow" to the left should be remembered. - int64_t borrow = 0; - for (unsigned i = 0; i < n; ++i) { - uint64_t p = uint64_t(qp) * uint64_t(v[i]); - int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p); - u[j+i] = Lo_32(subres); - borrow = Hi_32(p) - Hi_32(subres); - } - bool isNeg = u[j+n] < borrow; - u[j+n] -= Lo_32(borrow); - - // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was - // negative, go to step D6; otherwise go on to step D7. - q[j] = Lo_32(qp); - if (isNeg) { - // D6. [Add back]. The probability that this step is necessary is very - // small, on the order of only 2/b. Make sure that test data accounts for - // this possibility. Decrease q[j] by 1 - q[j]--; - // and add (0v[n-1]...v[1]v[0]) to (u[j+n]u[j+n-1]...u[j+1]u[j]). - // A carry will occur to the left of u[j+n], and it should be ignored - // since it cancels with the borrow that occurred in D4. - bool carry = false; - for (unsigned i = 0; i < n; i++) { - uint32_t limit = std::min(u[j+i],v[i]); - u[j+i] += v[i] + carry; - carry = u[j+i] < limit || (carry && u[j+i] == limit); - } - u[j+n] += carry; - } - - // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. - } while (--j >= 0); - - // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired - // remainder may be obtained by dividing u[...] by d. If r is non-null we - // compute the remainder (urem uses this). - if (r) { - // The value d is expressed by the "shift" value above since we avoided - // multiplication by d by using a shift left. So, all we have to do is - // shift right here. - if (shift) { - uint32_t carry = 0; - for (int i = n-1; i >= 0; i--) { - r[i] = (u[i] >> shift) | carry; - carry = u[i] << (32 - shift); - } - } else { - for (int i = n-1; i >= 0; i--) { - r[i] = u[i]; - } - } - } -} - -// Implementation ported from LLVM/lib/Support/APInt.cpp -static void bigint_unsigned_division(const BigInt *op1, const BigInt *op2, BigInt *Quotient, BigInt *Remainder) { - Cmp cmp = bigint_cmp(op1, op2); - if (cmp == CmpLT) { - if (Quotient != nullptr) { - bigint_init_unsigned(Quotient, 0); - } - if (Remainder != nullptr) { - bigint_init_bigint(Remainder, op1); - } - return; - } - if (cmp == CmpEQ) { - if (Quotient != nullptr) { - bigint_init_unsigned(Quotient, 1); - } - if (Remainder != nullptr) { - bigint_init_unsigned(Remainder, 0); - } - return; - } - - const uint64_t *LHS = bigint_ptr(op1); - const uint64_t *RHS = bigint_ptr(op2); - unsigned lhsWords = op1->digit_count; - unsigned rhsWords = op2->digit_count; - - // First, compose the values into an array of 32-bit words instead of - // 64-bit words. This is a necessity of both the "short division" algorithm - // and the Knuth "classical algorithm" which requires there to be native - // operations for +, -, and * on an m bit value with an m*2 bit result. We - // can't use 64-bit operands here because we don't have native results of - // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't - // work on large-endian machines. - unsigned n = rhsWords * 2; - unsigned m = (lhsWords * 2) - n; - - // Allocate space for the temporary values we need either on the stack, if - // it will fit, or on the heap if it won't. - uint32_t SPACE[128]; - uint32_t *U = nullptr; - uint32_t *V = nullptr; - uint32_t *Q = nullptr; - uint32_t *R = nullptr; - if ((Remainder?4:3)*n+2*m+1 <= 128) { - U = &SPACE[0]; - V = &SPACE[m+n+1]; - Q = &SPACE[(m+n+1) + n]; - if (Remainder) - R = &SPACE[(m+n+1) + n + (m+n)]; - } else { - U = new uint32_t[m + n + 1]; - V = new uint32_t[n]; - Q = new uint32_t[m+n]; - if (Remainder) - R = new uint32_t[n]; - } - - // Initialize the dividend - memset(U, 0, (m+n+1)*sizeof(uint32_t)); - for (unsigned i = 0; i < lhsWords; ++i) { - uint64_t tmp = LHS[i]; - U[i * 2] = Lo_32(tmp); - U[i * 2 + 1] = Hi_32(tmp); - } - U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm. - - // Initialize the divisor - memset(V, 0, (n)*sizeof(uint32_t)); - for (unsigned i = 0; i < rhsWords; ++i) { - uint64_t tmp = RHS[i]; - V[i * 2] = Lo_32(tmp); - V[i * 2 + 1] = Hi_32(tmp); - } - - // initialize the quotient and remainder - memset(Q, 0, (m+n) * sizeof(uint32_t)); - if (Remainder) - memset(R, 0, n * sizeof(uint32_t)); - - // Now, adjust m and n for the Knuth division. n is the number of words in - // the divisor. m is the number of words by which the dividend exceeds the - // divisor (i.e. m+n is the length of the dividend). These sizes must not - // contain any zero words or the Knuth algorithm fails. - for (unsigned i = n; i > 0 && V[i-1] == 0; i--) { - n--; - m++; - } - for (unsigned i = m+n; i > 0 && U[i-1] == 0; i--) - m--; - - // If we're left with only a single word for the divisor, Knuth doesn't work - // so we implement the short division algorithm here. This is much simpler - // and faster because we are certain that we can divide a 64-bit quantity - // by a 32-bit quantity at hardware speed and short division is simply a - // series of such operations. This is just like doing short division but we - // are using base 2^32 instead of base 10. - assert(n != 0 && "Divide by zero?"); - if (n == 1) { - uint32_t divisor = V[0]; - uint32_t remainder = 0; - for (int i = m; i >= 0; i--) { - uint64_t partial_dividend = Make_64(remainder, U[i]); - if (partial_dividend == 0) { - Q[i] = 0; - remainder = 0; - } else if (partial_dividend < divisor) { - Q[i] = 0; - remainder = Lo_32(partial_dividend); - } else if (partial_dividend == divisor) { - Q[i] = 1; - remainder = 0; - } else { - Q[i] = Lo_32(partial_dividend / divisor); - remainder = Lo_32(partial_dividend - (Q[i] * divisor)); - } - } - if (R) - R[0] = remainder; - } else { - // Now we're ready to invoke the Knuth classical divide algorithm. In this - // case n > 1. - KnuthDiv(U, V, Q, R, m, n); - } - - // If the caller wants the quotient - if (Quotient) { - Quotient->is_negative = false; - Quotient->digit_count = lhsWords; - if (lhsWords == 1) { - Quotient->data.digit = Make_64(Q[1], Q[0]); - } else { - Quotient->data.digits = heap::c_allocator.allocate(lhsWords); - for (size_t i = 0; i < lhsWords; i += 1) { - Quotient->data.digits[i] = Make_64(Q[i*2+1], Q[i*2]); - } - } - } - - // If the caller wants the remainder - if (Remainder) { - Remainder->is_negative = false; - Remainder->digit_count = rhsWords; - if (rhsWords == 1) { - Remainder->data.digit = Make_64(R[1], R[0]); - } else { - Remainder->data.digits = heap::c_allocator.allocate(rhsWords); - for (size_t i = 0; i < rhsWords; i += 1) { - Remainder->data.digits[i] = Make_64(R[i*2+1], R[i*2]); - } - } - } -} - -void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(op2->digit_count != 0); // division by zero - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->data.digit = op1_digits[0] / op2_digits[0]; - dest->digit_count = 1; - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); - return; - } - if (op2->digit_count == 1 && op2_digits[0] == 1) { - // X / 1 == X - bigint_init_bigint(dest, op1); - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); - return; - } - - const BigInt *op1_positive; - BigInt op1_positive_data; - if (op1->is_negative) { - bigint_negate(&op1_positive_data, op1); - op1_positive = &op1_positive_data; - } else { - op1_positive = op1; - } - - const BigInt *op2_positive; - BigInt op2_positive_data; - if (op2->is_negative) { - bigint_negate(&op2_positive_data, op2); - op2_positive = &op2_positive_data; - } else { - op2_positive = op2; - } - - bigint_unsigned_division(op1_positive, op2_positive, dest, nullptr); - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); -} - -void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->is_negative != op2->is_negative) { - bigint_div_trunc(dest, op1, op2); - BigInt mult_again = {0}; - bigint_mul(&mult_again, dest, op2); - mult_again.is_negative = op1->is_negative; - if (bigint_cmp(&mult_again, op1) != CmpEQ) { - BigInt tmp = {0}; - bigint_init_bigint(&tmp, dest); - BigInt neg_one = {0}; - bigint_init_signed(&neg_one, -1); - bigint_add(dest, &tmp, &neg_one); - } - bigint_normalize(dest); - } else { - bigint_div_trunc(dest, op1, op2); - } -} - -void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(op2->digit_count != 0); // division by zero - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->data.digit = op1_digits[0] % op2_digits[0]; - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) { - // special case this divisor - bigint_init_unsigned(dest, op1_digits[0]); - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - - if (op2->digit_count == 1 && op2_digits[0] == 1) { - // X % 1 == 0 - bigint_init_unsigned(dest, 0); - return; - } - - const BigInt *op1_positive; - BigInt op1_positive_data; - if (op1->is_negative) { - bigint_negate(&op1_positive_data, op1); - op1_positive = &op1_positive_data; - } else { - op1_positive = op1; - } - - const BigInt *op2_positive; - BigInt op2_positive_data; - if (op2->is_negative) { - bigint_negate(&op2_positive_data, op2); - op2_positive = &op2_positive_data; - } else { - op2_positive = op2; - } - - bigint_unsigned_division(op1_positive, op2_positive, nullptr, dest); - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->is_negative) { - BigInt first_rem; - bigint_rem(&first_rem, op1, op2); - first_rem.is_negative = !op2->is_negative; - BigInt op2_minus_rem; - bigint_add(&op2_minus_rem, op2, &first_rem); - bigint_rem(dest, &op2_minus_rem, op2); - dest->is_negative = false; - } else { - bigint_rem(dest, op1, op2); - dest->is_negative = false; - } -} - -void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_or(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] | op2_digits[0]; - bigint_normalize(dest); - return; - } - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - for (size_t i = 0; i < dest->digit_count; i += 1) { - uint64_t digit = 0; - if (i < op1->digit_count) { - digit |= op1_digits[i]; - } - if (i < op2->digit_count) { - digit |= op2_digits[i]; - } - dest->data.digits[i] = digit; - } - bigint_normalize(dest); - } -} - -void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0 || op2->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_and(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] & op2_digits[0]; - bigint_normalize(dest); - return; - } - - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - - size_t i = 0; - for (; i < op1->digit_count && i < op2->digit_count; i += 1) { - dest->data.digits[i] = op1_digits[i] & op2_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - dest->data.digits[i] = 0; - } - bigint_normalize(dest); - } -} - -void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_xor(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - assert(op1->digit_count > 0 && op2->digit_count > 0); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] ^ op2_digits[0]; - bigint_normalize(dest); - return; - } - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - size_t i = 0; - for (; i < op1->digit_count && i < op2->digit_count; i += 1) { - dest->data.digits[i] = op1_digits[i] ^ op2_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - if (i < op1->digit_count) { - dest->data.digits[i] = op1_digits[i]; - } else if (i < op2->digit_count) { - dest->data.digits[i] = op2_digits[i]; - } else { - zig_unreachable(); - } - } - bigint_normalize(dest); - } -} - -void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(!op2->is_negative); - - if (op2->digit_count == 0) { - bigint_init_bigint(dest, op1); - return; - } - - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (op2->digit_count != 1) { - zig_panic("TODO shift left by amount greater than 64 bit integer"); - } - - const uint64_t *op1_digits = bigint_ptr(op1); - uint64_t shift_amt = bigint_as_unsigned(op2); - - if (op1->digit_count == 1 && shift_amt < 64) { - dest->data.digit = op1_digits[0] << shift_amt; - if (dest->data.digit >> shift_amt == op1_digits[0]) { - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - return; - } - } - - uint64_t digit_shift_count = shift_amt / 64; - uint64_t leftover_shift_count = shift_amt % 64; - - dest->data.digits = heap::c_allocator.allocate(op1->digit_count + digit_shift_count + 1); - dest->digit_count = digit_shift_count; - uint64_t carry = 0; - for (size_t i = 0; i < op1->digit_count; i += 1) { - uint64_t digit = op1_digits[i]; - dest->data.digits[dest->digit_count] = carry | (digit << leftover_shift_count); - dest->digit_count += 1; - if (leftover_shift_count > 0) { - carry = digit >> (64 - leftover_shift_count); - } else { - carry = 0; - } - } - dest->data.digits[dest->digit_count] = carry; - dest->digit_count += 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_shl(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(!op2->is_negative); - - if (op1->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - - if (op2->digit_count != 1) { - zig_panic("TODO shift right by amount greater than 64 bit integer"); - } - - const uint64_t *op1_digits = bigint_ptr(op1); - uint64_t shift_amt = bigint_as_unsigned(op2); - - if (op1->digit_count == 1) { - dest->data.digit = (shift_amt < 64) ? op1_digits[0] >> shift_amt : 0; - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - - size_t digit_shift_count = shift_amt / 64; - size_t leftover_shift_count = shift_amt % 64; - - if (digit_shift_count >= op1->digit_count) { - return bigint_init_unsigned(dest, 0); - } - - dest->digit_count = op1->digit_count - digit_shift_count; - uint64_t *digits; - if (dest->digit_count == 1) { - digits = &dest->data.digit; - } else { - digits = heap::c_allocator.allocate(dest->digit_count); - dest->data.digits = digits; - } - - uint64_t carry = 0; - for (size_t op_digit_index = op1->digit_count - 1;;) { - uint64_t digit = op1_digits[op_digit_index]; - size_t dest_digit_index = op_digit_index - digit_shift_count; - digits[dest_digit_index] = carry | (digit >> leftover_shift_count); - carry = (leftover_shift_count != 0) ? (digit << (64 - leftover_shift_count)) : 0; - - if (dest_digit_index == 0) { break; } - op_digit_index -= 1; - } - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_negate(BigInt *dest, const BigInt *op) { - bigint_init_bigint(dest, op); - dest->is_negative = !dest->is_negative; - bigint_normalize(dest); -} - -void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - BigInt zero; - bigint_init_unsigned(&zero, 0); - bigint_sub_wrap(dest, &zero, op, bit_count, is_signed); -} - -void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - if (bit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (is_signed) { - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, op, bit_count); - - BigInt inverted = {0}; - bigint_not(&inverted, &twos_comp, bit_count, false); - - from_twos_complement(dest, &inverted, bit_count, true); - return; - } - - assert(!op->is_negative); - - dest->is_negative = false; - const uint64_t *op_digits = bigint_ptr(op); - if (bit_count <= 64) { - dest->digit_count = 1; - if (op->digit_count == 0) { - if (bit_count == 64) { - dest->data.digit = UINT64_MAX; - } else { - dest->data.digit = (1ULL << bit_count) - 1; - } - } else if (op->digit_count == 1) { - dest->data.digit = ~op_digits[0]; - if (bit_count != 64) { - uint64_t mask = (1ULL << bit_count) - 1; - dest->data.digit &= mask; - } - } - bigint_normalize(dest); - return; - } - dest->digit_count = (bit_count + 63) / 64; - assert(dest->digit_count >= op->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - size_t i = 0; - for (; i < op->digit_count; i += 1) { - dest->data.digits[i] = ~op_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - dest->data.digits[i] = 0xffffffffffffffffULL; - } - size_t digit_index = dest->digit_count - 1; - size_t digit_bit_index = bit_count % 64; - if (digit_bit_index != 0) { - uint64_t mask = (1ULL << digit_bit_index) - 1; - dest->data.digits[digit_index] &= mask; - } - bigint_normalize(dest); -} - -void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - BigInt twos_comp; - to_twos_complement(&twos_comp, op, bit_count); - from_twos_complement(dest, &twos_comp, bit_count, is_signed); -} - -Cmp bigint_cmp(const BigInt *op1, const BigInt *op2) { - if (op1->is_negative && !op2->is_negative) { - return CmpLT; - } else if (!op1->is_negative && op2->is_negative) { - return CmpGT; - } else if (op1->digit_count > op2->digit_count) { - return op1->is_negative ? CmpLT : CmpGT; - } else if (op2->digit_count > op1->digit_count) { - return op1->is_negative ? CmpGT : CmpLT; - } else if (op1->digit_count == 0) { - return CmpEQ; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - for (size_t i = op1->digit_count - 1; ;) { - uint64_t op1_digit = op1_digits[i]; - uint64_t op2_digit = op2_digits[i]; - - if (op1_digit > op2_digit) { - return op1->is_negative ? CmpLT : CmpGT; - } - if (op1_digit < op2_digit) { - return op1->is_negative ? CmpGT : CmpLT; - } - - if (i == 0) { - return CmpEQ; - } - i -= 1; - } -} - -void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) { - if (op->digit_count == 0) { - buf_append_char(buf, '0'); - return; - } - if (op->is_negative) { - buf_append_char(buf, '-'); - } - if (op->digit_count == 1 && base == 10) { - buf_appendf(buf, "%" ZIG_PRI_u64, op->data.digit); - return; - } - if (op->digit_count == 1 && base == 16) { - buf_appendf(buf, "%" ZIG_PRI_x64, op->data.digit); - return; - } - size_t first_digit_index = buf_len(buf); - - BigInt digit_bi = {0}; - BigInt a1 = {0}; - BigInt a2 = {0}; - - BigInt *a = &a1; - BigInt *other_a = &a2; - bigint_init_bigint(a, op); - - BigInt base_bi = {0}; - bigint_init_unsigned(&base_bi, base); - - for (;;) { - bigint_rem(&digit_bi, a, &base_bi); - uint8_t digit = bigint_as_unsigned(&digit_bi); - buf_append_char(buf, digit_to_char(digit, false)); - bigint_div_trunc(other_a, a, &base_bi); - { - BigInt *tmp = a; - a = other_a; - other_a = tmp; - } - if (bigint_cmp_zero(a) == CmpEQ) { - break; - } - } - - // reverse - for (size_t i = first_digit_index; i < buf_len(buf) / 2; i += 1) { - size_t other_i = buf_len(buf) + first_digit_index - i - 1; - uint8_t tmp = buf_ptr(buf)[i]; - buf_ptr(buf)[i] = buf_ptr(buf)[other_i]; - buf_ptr(buf)[other_i] = tmp; - } -} - -size_t bigint_popcount_unsigned(const BigInt *bi) { - assert(!bi->is_negative); - if (bi->digit_count == 0) - return 0; - - size_t count = 0; - size_t bit_count = bi->digit_count * 64; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(bi, i)) - count += 1; - } - return count; -} - -size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count) { - if (bit_count == 0) - return 0; - if (bi->digit_count == 0) - return 0; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, bi, bit_count); - - size_t count = 0; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(&twos_comp, i)) - count += 1; - } - return count; -} - -size_t bigint_ctz(const BigInt *bi, size_t bit_count) { - if (bit_count == 0) - return 0; - if (bi->digit_count == 0) - return bit_count; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, bi, bit_count); - - size_t count = 0; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(&twos_comp, i)) - return count; - count += 1; - } - return count; -} - -size_t bigint_clz(const BigInt *bi, size_t bit_count) { - if (bi->is_negative || bit_count == 0) - return 0; - if (bi->digit_count == 0) - return bit_count; - - size_t count = 0; - for (size_t i = bit_count - 1;;) { - if (bit_at_index(bi, i)) - return count; - count += 1; - - if (i == 0) break; - i -= 1; - } - return count; -} - -static uint64_t bigint_as_unsigned(const BigInt *bigint) { - assert(!bigint->is_negative); - if (bigint->digit_count == 0) { - return 0; - } else if (bigint->digit_count == 1) { - return bigint->data.digit; - } else { - zig_unreachable(); - } -} - -uint64_t bigint_as_u64(const BigInt *bigint) -{ - return bigint_as_unsigned(bigint); -} - -uint32_t bigint_as_u32(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - uint32_t value32 = (uint32_t)value64; - assert (value64 == value32); - return value32; -} - -uint8_t bigint_as_u8(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - uint8_t value8 = (uint8_t)value64; - assert (value64 == value8); - return value8; -} - -size_t bigint_as_usize(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - size_t valueUsize = (size_t)value64; - assert (value64 == valueUsize); - return valueUsize; -} - -int64_t bigint_as_signed(const BigInt *bigint) { - if (bigint->digit_count == 0) { - return 0; - } else if (bigint->digit_count == 1) { - if (bigint->is_negative) { - if (bigint->data.digit <= 9223372036854775808ULL) { - return (-((int64_t)(bigint->data.digit - 1))) - 1; - } else { - zig_unreachable(); - } - } else { - return bigint->data.digit; - } - } else { - zig_unreachable(); - } -} - -Cmp bigint_cmp_zero(const BigInt *op) { - if (op->digit_count == 0) { - return CmpEQ; - } - return op->is_negative ? CmpLT : CmpGT; -} - -uint32_t bigint_hash(BigInt const *x) { - if (x->digit_count == 0) { - return 0; - } else { - return bigint_ptr(x)[0]; - } -} - -bool bigint_eql(BigInt const *a, BigInt const *b) { - return bigint_cmp(a, b) == CmpEQ; -} - -void bigint_incr(BigInt *x) { - if (x->digit_count == 0) { - bigint_init_unsigned(x, 1); - return; - } - - if (x->digit_count == 1) { - if (x->is_negative && x->data.digit != 0) { - x->data.digit -= 1; - return; - } else if (!x->is_negative && x->data.digit != UINT64_MAX) { - x->data.digit += 1; - return; - } - } - - BigInt copy; - bigint_init_bigint(©, x); - - BigInt one; - bigint_init_unsigned(&one, 1); - - bigint_add(x, ©, &one); -} - -void bigint_decr(BigInt *x) { - if (x->digit_count == 0) { - bigint_init_signed(x, -1); - return; - } - - if (x->digit_count == 1) { - if (x->is_negative && x->data.digit != UINT64_MAX) { - x->data.digit += 1; - return; - } else if (!x->is_negative && x->data.digit != 0) { - x->data.digit -= 1; - return; - } - } - - BigInt copy; - bigint_init_bigint(©, x); - - BigInt neg_one; - bigint_init_signed(&neg_one, -1); - - bigint_add(x, ©, &neg_one); -} diff --git a/src/stage1/bigint.hpp b/src/stage1/bigint.hpp deleted file mode 100644 index 7d30fb168970..000000000000 --- a/src/stage1/bigint.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BIGINT_HPP -#define ZIG_BIGINT_HPP - -#include -#include - -struct BigInt { - size_t digit_count; - union { - uint64_t digit; - uint64_t *digits; // Least significant digit first - } data; - bool is_negative; -}; - -struct Buf; -struct BigFloat; - -enum Cmp { - CmpLT, - CmpGT, - CmpEQ, -}; - -void bigint_init_unsigned(BigInt *dest, uint64_t x); -void bigint_init_signed(BigInt *dest, int64_t x); -void bigint_init_bigint(BigInt *dest, const BigInt *src); -void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); -void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative); -void bigint_deinit(BigInt *bi); - -// panics if number won't fit -uint64_t bigint_as_u64(const BigInt *bigint); -uint32_t bigint_as_u32(const BigInt *bigint); -uint8_t bigint_as_u8(const BigInt *bigint); -size_t bigint_as_usize(const BigInt *bigint); - -int64_t bigint_as_signed(const BigInt *bigint); - -static inline const uint64_t *bigint_ptr(const BigInt *bigint) { - if (bigint->digit_count == 1) { - return &bigint->data.digit; - } else { - return bigint->data.digits; - } -} - -bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed); -void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); -void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, - bool is_signed); -void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2); -void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2); -void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_negate(BigInt *dest, const BigInt *op); -void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); -void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); -void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); - -Cmp bigint_cmp(const BigInt *op1, const BigInt *op2); - -void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base); - -size_t bigint_ctz(const BigInt *bi, size_t bit_count); -size_t bigint_clz(const BigInt *bi, size_t bit_count); -size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count); -size_t bigint_popcount_unsigned(const BigInt *bi); - -size_t bigint_bits_needed(const BigInt *op); - - -// convenience functions -Cmp bigint_cmp_zero(const BigInt *op); - -void bigint_incr(BigInt *value); -void bigint_decr(BigInt *value); - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result); - -uint32_t bigint_hash(BigInt const *x); -bool bigint_eql(BigInt const *a, BigInt const *b); - -void bigint_add_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_sub_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_mul_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_shl_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -#endif diff --git a/src/stage1/buffer.cpp b/src/stage1/buffer.cpp deleted file mode 100644 index 86435e0f1496..000000000000 --- a/src/stage1/buffer.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "buffer.hpp" -#include -#include -#include - -Buf *buf_vprintf(const char *format, va_list ap) { - va_list ap2; - va_copy(ap2, ap); - - int len1 = vsnprintf(nullptr, 0, format, ap); - assert(len1 >= 0); - - size_t required_size = len1 + 1; - - Buf *buf = buf_alloc_fixed(len1); - - int len2 = vsnprintf(buf_ptr(buf), required_size, format, ap2); - assert(len2 == len1); - - va_end(ap2); - - return buf; -} - -Buf *buf_sprintf(const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *result = buf_vprintf(format, ap); - va_end(ap); - return result; -} - -void buf_appendf(Buf *buf, const char *format, ...) { - assert(buf->list.length); - va_list ap, ap2; - va_start(ap, format); - va_copy(ap2, ap); - - int len1 = vsnprintf(nullptr, 0, format, ap); - assert(len1 >= 0); - - size_t required_size = len1 + 1; - - size_t orig_len = buf_len(buf); - - buf_resize(buf, orig_len + len1); - - int len2 = vsnprintf(buf_ptr(buf) + orig_len, required_size, format, ap2); - assert(len2 == len1); - - va_end(ap2); - va_end(ap); -} - -// these functions are not static inline so they can be better used as template parameters -bool buf_eql_buf(Buf *buf, Buf *other) { - return buf_eql_mem(buf, buf_ptr(other), buf_len(other)); -} - -uint32_t buf_hash(Buf *buf) { - assert(buf->list.length); - size_t interval = buf->list.length / 256; - if (interval == 0) - interval = 1; - // FNV 32-bit hash - uint32_t h = 2166136261; - for (size_t i = 0; i < buf_len(buf); i += interval) { - h = h ^ ((uint8_t)buf->list.at(i)); - h = h * 16777619; - } - return h; -} diff --git a/src/stage1/buffer.hpp b/src/stage1/buffer.hpp deleted file mode 100644 index d8a31b1bf416..000000000000 --- a/src/stage1/buffer.hpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BUFFER_HPP -#define ZIG_BUFFER_HPP - -#include "list.hpp" - -#include -#include -#include - -#define BUF_INIT {{0}} - -// Note, you must call one of the alloc, init, or resize functions to have an -// initialized buffer. The assertions should help with this. -struct Buf { - ZigList list; -}; - -Buf *buf_sprintf(const char *format, ...) - ATTRIBUTE_PRINTF(1, 2); -Buf *buf_vprintf(const char *format, va_list ap); - -static inline size_t buf_len(const Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.length - 1; -} - -static inline char *buf_ptr(Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.items; -} - -static inline const char *buf_ptr(const Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.items; -} - -static inline void buf_resize(Buf *buf, size_t new_len) { - buf->list.resize(new_len + 1); - buf->list.at(buf_len(buf)) = 0; -} - -static inline Buf *buf_alloc_fixed(size_t size) { - Buf *buf = heap::c_allocator.create(); - buf_resize(buf, size); - return buf; -} - -static inline Buf *buf_alloc(void) { - return buf_alloc_fixed(0); -} - -static inline void buf_deinit(Buf *buf) { - buf->list.deinit(); -} - -static inline void buf_destroy(Buf *buf) { - buf_deinit(buf); - heap::c_allocator.destroy(buf); -} - -static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) { - assert(len != SIZE_MAX); - buf->list.resize(len + 1); - memcpy(buf_ptr(buf), ptr, len); - buf->list.at(buf_len(buf)) = 0; -} - -static inline void buf_init_from_str(Buf *buf, const char *str) { - buf_init_from_mem(buf, str, strlen(str)); -} - -static inline void buf_init_from_buf(Buf *buf, Buf *other) { - buf_init_from_mem(buf, buf_ptr(other), buf_len(other)); -} - -static inline Buf *buf_create_from_mem(const char *ptr, size_t len) { - assert(len != SIZE_MAX); - Buf *buf = heap::c_allocator.create(); - buf_init_from_mem(buf, ptr, len); - return buf; -} - -static inline Buf *buf_create_from_slice(Slice slice) { - return buf_create_from_mem((const char *)slice.ptr, slice.len); -} - -static inline Buf *buf_create_from_str(const char *str) { - return buf_create_from_mem(str, strlen(str)); -} - -static inline Buf *buf_create_from_buf(Buf *buf) { - return buf_create_from_mem(buf_ptr(buf), buf_len(buf)); -} - -static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) { - assert(in_buf->list.length); - assert(start != SIZE_MAX); - assert(end != SIZE_MAX); - assert(start < buf_len(in_buf)); - assert(end <= buf_len(in_buf)); - Buf *out_buf = heap::c_allocator.create(); - out_buf->list.resize(end - start + 1); - memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start); - out_buf->list.at(buf_len(out_buf)) = 0; - return out_buf; -} - -static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - assert(mem_len != SIZE_MAX); - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + mem_len); - memcpy(buf_ptr(buf) + old_len, mem, mem_len); - buf->list.at(buf_len(buf)) = 0; -} - -static inline void buf_append_str(Buf *buf, const char *str) { - assert(buf->list.length); - buf_append_mem(buf, str, strlen(str)); -} - -static inline void buf_append_buf(Buf *buf, Buf *append_buf) { - assert(buf->list.length); - buf_append_mem(buf, buf_ptr(append_buf), buf_len(append_buf)); -} - -static inline void buf_append_char(Buf *buf, uint8_t c) { - assert(buf->list.length); - buf_append_mem(buf, (const char *)&c, 1); -} - -void buf_appendf(Buf *buf, const char *format, ...) - ATTRIBUTE_PRINTF(2, 3); - -static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_eql_mem_ignore_case(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - return mem_eql_mem_ignore_case(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_eql_str(Buf *buf, const char *str) { - assert(buf->list.length); - return buf_eql_mem(buf, str, strlen(str)); -} - -static inline bool buf_eql_str_ignore_case(Buf *buf, const char *str) { - assert(buf->list.length); - return buf_eql_mem_ignore_case(buf, str, strlen(str)); -} - -static inline bool buf_starts_with_mem(Buf *buf, const char *mem, size_t mem_len) { - if (buf_len(buf) < mem_len) { - return false; - } - return memcmp(buf_ptr(buf), mem, mem_len) == 0; -} - -static inline bool buf_starts_with_buf(Buf *buf, Buf *sub) { - return buf_starts_with_mem(buf, buf_ptr(sub), buf_len(sub)); -} - -static inline bool buf_starts_with_str(Buf *buf, const char *str) { - return buf_starts_with_mem(buf, str, strlen(str)); -} - -static inline bool buf_ends_with_mem(Buf *buf, const char *mem, size_t mem_len) { - return mem_ends_with_mem(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_ends_with_str(Buf *buf, const char *str) { - return buf_ends_with_mem(buf, str, strlen(str)); -} - -bool buf_eql_buf(Buf *buf, Buf *other); -uint32_t buf_hash(Buf *buf); - -static inline void buf_upcase(Buf *buf) { - for (size_t i = 0; i < buf_len(buf); i += 1) { - buf_ptr(buf)[i] = (char)toupper(buf_ptr(buf)[i]); - } -} - -static inline Slice buf_to_slice(Buf *buf) { - return Slice{reinterpret_cast(buf_ptr(buf)), buf_len(buf)}; -} - -static inline void buf_replace(Buf* buf, char from, char to) { - const size_t count = buf_len(buf); - char* ptr = buf_ptr(buf); - for (size_t i = 0; i < count; ++i) { - char& l = ptr[i]; - if (l == from) - l = to; - } -} - -#endif diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp deleted file mode 100644 index 0b6523edec40..000000000000 --- a/src/stage1/codegen.cpp +++ /dev/null @@ -1,11034 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "analyze.hpp" -#include "codegen.hpp" -#include "errmsg.hpp" -#include "error.hpp" -#include "hash_map.hpp" -#include "ir.hpp" -#include "os.hpp" -#include "target.hpp" -#include "util.hpp" -#include "zig_llvm.h" -#include "stage2.h" -#include "softfloat.hpp" -#include "zigendian.h" - -#include -#include -#include -#include - -enum ResumeId { - ResumeIdManual, - ResumeIdReturn, - ResumeIdCall, -}; - -static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) { - ZigPackage *entry = heap::c_allocator.create(); - entry->package_table.init(4); - buf_init_from_str(&entry->root_src_dir, root_src_dir); - buf_init_from_str(&entry->root_src_path, root_src_path); - buf_init_from_str(&entry->pkg_path, pkg_path); - return entry; -} - -ZigPackage *new_anonymous_package() { - return new_package("", "", ""); -} - -static const char *symbols_that_llvm_depends_on[] = { - "memcpy", - "memset", - "sqrt", - "powi", - "sin", - "cos", - "pow", - "exp", - "exp2", - "log", - "log10", - "log2", - "fma", - "fmaf", - "fmal", - "fmaq", - "fabs", - "minnum", - "maxnum", - "copysign", - "floor", - "ceil", - "trunc", - "rint", - "nearbyint", - "round", - // TODO probably all of compiler-rt needs to go here -}; - -void codegen_set_strip(CodeGen *g, bool strip) { - g->strip_debug_symbols = strip; - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } -} - -static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type); -static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); -static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); -static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name); -static void generate_error_name_table(CodeGen *g); -static bool value_is_all_undef(CodeGen *g, ZigValue *const_val); -static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr); -static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment); -static LLVMValueRef gen_await_early_return(CodeGen *g, Stage1AirInst *source_instr, - LLVMTypeRef target_frame_struct_llvm_ty, LLVMValueRef target_frame_ptr, - ZigType *result_type, ZigType *ptr_result_type, LLVMValueRef result_loc, bool non_async); - -static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { - unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); - assert(kind_id != 0); - LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMAttrStr(LLVMValueRef val, LLVMAttributeIndex attr_index, - const char *attr_name, const char *attr_val) -{ - LLVMAttributeRef llvm_attr = LLVMCreateStringAttribute(LLVMGetGlobalContext(), - attr_name, (unsigned)strlen(attr_name), attr_val, (unsigned)strlen(attr_val)); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMAttrInt(LLVMValueRef val, LLVMAttributeIndex attr_index, - const char *attr_name, uint64_t attr_val) -{ - unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); - assert(kind_id != 0); - LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, attr_val); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMFnAttr(LLVMValueRef fn_val, const char *attr_name) { - return addLLVMAttr(fn_val, -1, attr_name); -} - -static void addLLVMFnAttrStr(LLVMValueRef fn_val, const char *attr_name, const char *attr_val) { - return addLLVMAttrStr(fn_val, -1, attr_name, attr_val); -} - -static void addLLVMFnAttrInt(LLVMValueRef fn_val, const char *attr_name, uint64_t attr_val) { - return addLLVMAttrInt(fn_val, -1, attr_name, attr_val); -} - -static void addLLVMArgAttr(LLVMValueRef fn_val, unsigned param_index, const char *attr_name) { - return addLLVMAttr(fn_val, param_index + 1, attr_name); -} - -static void addLLVMArgAttrInt(LLVMValueRef fn_val, unsigned param_index, const char *attr_name, uint64_t attr_val) { - return addLLVMAttrInt(fn_val, param_index + 1, attr_name, attr_val); -} - -static bool is_symbol_available(CodeGen *g, const char *name) { - Buf *buf_name = buf_create_from_str(name); - bool result = - g->exported_symbol_names.maybe_get(buf_name) == nullptr && - g->external_symbol_names.maybe_get(buf_name) == nullptr; - buf_destroy(buf_name); - return result; -} - -static const char *get_mangled_name(CodeGen *g, const char *original_name) { - if (is_symbol_available(g, original_name)) - return original_name; - - int n = 0; - for (;; n += 1) { - const char *new_name = buf_ptr(buf_sprintf("%s.%d", original_name, n)); - if (is_symbol_available(g, new_name)) { - return new_name; - } - } -} - -// Sync this with emit_error_unless_callconv_allowed_for_target in analyze.cpp -static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionInline: - return ZigLLVM_Fast; - case CallingConventionC: - return ZigLLVM_C; - case CallingConventionNaked: - zig_unreachable(); - case CallingConventionStdcall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_StdCall; - case CallingConventionFastcall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_FastCall; - case CallingConventionVectorcall: - if (g->zig_target->arch == ZigLLVM_x86) - return ZigLLVM_X86_VectorCall; - if (target_is_arm(g->zig_target) && - target_arch_pointer_bit_width(g->zig_target->arch) == 64) - return ZigLLVM_AArch64_VectorCall; - zig_unreachable(); - case CallingConventionThiscall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_ThisCall; - case CallingConventionAsync: - return ZigLLVM_Fast; - case CallingConventionAPCS: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_APCS; - case CallingConventionAAPCS: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_AAPCS; - case CallingConventionAAPCSVFP: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_AAPCS_VFP; - case CallingConventionInterrupt: - if (g->zig_target->arch == ZigLLVM_x86 || - g->zig_target->arch == ZigLLVM_x86_64) - return ZigLLVM_X86_INTR; - if (g->zig_target->arch == ZigLLVM_avr) - return ZigLLVM_AVR_INTR; - if (g->zig_target->arch == ZigLLVM_msp430) - return ZigLLVM_MSP430_INTR; - zig_unreachable(); - case CallingConventionSignal: - assert(g->zig_target->arch == ZigLLVM_avr); - return ZigLLVM_AVR_SIGNAL; - case CallingConventionSysV: - assert(g->zig_target->arch == ZigLLVM_x86_64); - return ZigLLVM_X86_64_SysV; - case CallingConventionWin64: - assert(g->zig_target->arch == ZigLLVM_x86_64); - return ZigLLVM_Win64; - case CallingConventionPtxKernel: - assert(g->zig_target->arch == ZigLLVM_nvptx || - g->zig_target->arch == ZigLLVM_nvptx64); - return ZigLLVM_PTX_Kernel; - case CallingConventionAmdgpuKernel: - assert(g->zig_target->arch == ZigLLVM_amdgcn); - return ZigLLVM_AMDGPU_KERNEL; - - } - zig_unreachable(); -} - -static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { - if (g->unwind_tables) { - addLLVMFnAttrInt(fn_val, "uwtable", 2); - } -} - -static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { - switch (id) { - case GlobalLinkageIdInternal: - return LLVMInternalLinkage; - case GlobalLinkageIdStrong: - return LLVMExternalLinkage; - case GlobalLinkageIdWeak: - if (is_extern) return LLVMExternalWeakLinkage; - return LLVMWeakODRLinkage; - case GlobalLinkageIdLinkOnce: - return LLVMLinkOnceODRLinkage; - } - zig_unreachable(); -} - -struct CalcLLVMFieldIndex { - uint32_t offset; - uint32_t field_index; -}; - -static void calc_llvm_field_index_add(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *ty) { - if (!type_has_bits(g, ty)) return; - uint32_t ty_align = get_abi_alignment(g, ty); - - if (calc->offset % ty_align != 0) { - uint32_t llvm_align = LLVMABIAlignmentOfType(g->target_data_ref, get_llvm_type(g, ty)); - - // Alignment according to Zig. - uint32_t adj_offset = calc->offset + (ty_align - (calc->offset % ty_align)); - // Alignment according to LLVM. - uint32_t adj_llvm_offset = (calc->offset % llvm_align) ? - calc->offset + (llvm_align - (calc->offset % llvm_align)) : - calc->offset; - // Cannot under-align structure fields. - assert(adj_offset >= adj_llvm_offset); - - // Zig will insert an extra padding field here. - if (adj_offset != adj_llvm_offset) - calc->field_index += 1; - - calc->offset = adj_offset; - } - calc->offset += ty->abi_size; - calc->field_index += 1; -} - -// label (grep this): [fn_frame_struct_layout] -static void frame_index_trace_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // function pointer - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // resume index - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // awaiter index - - if (type_has_bits(g, return_type)) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (callee's) - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (awaiter's) - calc_llvm_field_index_add(g, calc, return_type); // ReturnType - } -} - -static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) { - CalcLLVMFieldIndex calc = {0}; - frame_index_trace_arg_calc(g, &calc, return_type); - return calc.field_index; -} - -// label (grep this): [fn_frame_struct_layout] -static void frame_index_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) { - frame_index_trace_arg_calc(g, calc, return_type); - - if (codegen_fn_has_err_ret_tracing_arg(g, return_type)) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (callee's) - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (awaiter's) - } -} - -// label (grep this): [fn_frame_struct_layout] -static uint32_t frame_index_trace_stack(CodeGen *g, ZigFn *fn) { - size_t field_index = 6; - bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type); - if (have_stack_trace) { - field_index += 2; - } - field_index += fn->type_entry->data.fn.fn_type_id.param_count; - ZigType *locals_struct = fn->frame_type->data.frame.locals_struct; - TypeStructField *field = locals_struct->data.structure.fields[field_index]; - return field->gen_index; -} - - -static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) { - if (!g->have_err_ret_tracing) { - return UINT32_MAX; - } - if (fn_is_async(fn_table_entry)) { - return UINT32_MAX; - } - ZigType *fn_type = fn_table_entry->type_entry; - if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) { - return UINT32_MAX; - } - ZigType *return_type = fn_type->data.fn.fn_type_id.return_type; - bool first_arg_ret = type_has_bits(g, return_type) && handle_is_ptr(g, return_type); - return first_arg_ret ? 1 : 0; -} - -static void maybe_export_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) { - if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows && g->dll_export_fns) { - LLVMSetDLLStorageClass(global_value, LLVMDLLExportStorageClass); - } -} - -static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) { - if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) { - // TODO come up with a good explanation/understanding for why we never do - // DLLImportStorageClass. Empirically it only causes problems. But let's have - // this documented and then clean up the code accordingly. - //LLVMSetDLLStorageClass(global_value, LLVMDLLImportStorageClass); - } -} - -static bool cc_want_sret_attr(CallingConvention cc) { - switch (cc) { - case CallingConventionNaked: - zig_unreachable(); - case CallingConventionC: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - return true; - case CallingConventionAsync: - case CallingConventionUnspecified: - case CallingConventionInline: - return false; - } - zig_unreachable(); -} - -static void add_common_fn_attributes(CodeGen *g, LLVMValueRef llvm_fn) { - if (!g->red_zone) { - addLLVMFnAttr(llvm_fn, "noredzone"); - } - - addLLVMFnAttr(llvm_fn, "nounwind"); - add_uwtable_attr(g, llvm_fn); - addLLVMFnAttr(llvm_fn, "nobuiltin"); - - if (g->build_mode == BuildModeSmallRelease) { - // Optimize for small code size. - addLLVMFnAttr(llvm_fn, "minsize"); - addLLVMFnAttr(llvm_fn, "optsize"); - } - - if (g->zig_target->llvm_cpu_name != nullptr) { - ZigLLVMAddFunctionAttr(llvm_fn, "target-cpu", g->zig_target->llvm_cpu_name); - } - if (g->zig_target->llvm_cpu_features != nullptr) { - ZigLLVMAddFunctionAttr(llvm_fn, "target-features", g->zig_target->llvm_cpu_features); - } -} - -static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { - const char *unmangled_name = buf_ptr(&fn->symbol_name); - const char *symbol_name; - GlobalLinkageId linkage; - if (fn->body_node == nullptr) { - symbol_name = unmangled_name; - linkage = GlobalLinkageIdStrong; - } else if (fn->export_list.length == 0) { - symbol_name = get_mangled_name(g, unmangled_name); - linkage = GlobalLinkageIdInternal; - } else { - GlobalExport *fn_export = &fn->export_list.items[0]; - symbol_name = buf_ptr(&fn_export->name); - linkage = fn_export->linkage; - } - - CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc; - bool is_async = fn_is_async(fn); - - ZigType *fn_type = fn->type_entry; - // Make the raw_type_ref populated - resolve_llvm_types_fn(g, fn); - LLVMTypeRef fn_llvm_type = fn->raw_type_ref; - LLVMValueRef llvm_fn = nullptr; - if (fn->body_node == nullptr) { - assert(fn->proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; - - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - - // The compiler tries to deduplicate extern definitions by looking up - // their name, this was introduced to allow the declaration of the same - // extern function with differing prototypes. - // When Wasm is targeted this check becomes a problem as the user may - // declare two (or more) extern functions sharing the same name but - // imported from different modules! - // To overcome this problem we generate a mangled identifier out of the - // import and the function name, this name is only visible within the - // compiler as we're telling LLVM (using 'wasm-import-name' and - // 'wasm-import-name') what the real function name is and where to find - // it. - bool use_mangled_name = target_is_wasm(g->zig_target) && - fn_proto->is_extern && fn_proto->lib_name != nullptr; - // This is subtle but important to match libc symbols at static link time correctly. - // We treat "c" lib_name as a special library indicating that it should be defined - // in libc. But if we mangle a libc symbol name here with "c" module name, then wasm-ld cannot resolve - // the symbol. This is because at the static link time with wasm-ld, the linker does not - // take module names into account, and instead looking for a pure symbol name (i.e. function name) - // written into the ".linking" custom section (i.e. it does not use import section). - // This is the intended behavior of wasm-ld, because Wasm has a concept of host functions, - // which are undefined functions supposed to be resolved by host runtimes *with module names* - // at load times even if it is "static linked" with the linker. - use_mangled_name = use_mangled_name && (strcmp(buf_ptr(fn_proto->lib_name), "c") != 0); - // Pick a weird name to avoid collisions... - // This whole function should be burned to the ground. - Buf *mangled_symbol_buf = use_mangled_name ? - buf_sprintf("%s|%s", unmangled_name, buf_ptr(fn_proto->lib_name)) : - nullptr; - symbol_name = use_mangled_name ? - buf_ptr(mangled_symbol_buf) : unmangled_name; - - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name); - - if (existing_llvm_fn) { - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, fn_addrspace)); - } else { - Buf *buf_symbol_name = buf_create_from_str(symbol_name); - auto entry = g->exported_symbol_names.maybe_get(buf_symbol_name); - buf_destroy(buf_symbol_name); - - if (entry == nullptr) { - llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); - - if (use_mangled_name) { - // Note that "wasm-import-module"ed symbols will not be resolved - // in the future version of wasm-ld since the attribute basically means that - // "the symbol should be resolved at load time by runtimes", though - // the symbol is already mangled here and it is written into "linking" section - // used by wasm-ld to match symbols, so it should not be expected by users. - // tl;dr is that users should not put the lib_name specifier on extern statements - // if they want to link symbols with wasm-ld. - addLLVMFnAttrStr(llvm_fn, "wasm-import-name", unmangled_name); - addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); - } - } else { - assert(entry->value->id == TldIdFn); - TldFn *tld_fn = reinterpret_cast(entry->value); - // Make the raw_type_ref populated - resolve_llvm_types_fn(g, tld_fn->fn_entry); - tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name, - tld_fn->fn_entry->raw_type_ref); - llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, fn_addrspace)); - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - return llvm_fn; - } - - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - } - } else { - llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); - - for (size_t i = 1; i < fn->export_list.length; i += 1) { - GlobalExport *fn_export = &fn->export_list.items[i]; - LLVMAddAlias2(g->module, LLVMTypeOf(llvm_fn), 0, llvm_fn, buf_ptr(&fn_export->name)); - } - } - - if (cc == CallingConventionInline) - addLLVMFnAttr(llvm_fn, "alwaysinline"); - - if (fn->is_noinline || (cc != CallingConventionInline && fn->alignstack_value != 0)) - addLLVMFnAttr(llvm_fn, "noinline"); - - if (cc == CallingConventionNaked) { - addLLVMFnAttr(llvm_fn, "naked"); - } else { - ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc)); - } - - if (g->tsan_enabled) { - addLLVMFnAttr(llvm_fn, "sanitize_thread"); - } - - bool want_cold = fn->is_cold; - if (want_cold) { - ZigLLVMAddFunctionAttrCold(llvm_fn); - } - - - LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr)); - - if (linkage == GlobalLinkageIdInternal) { - LLVMSetUnnamedAddr(llvm_fn, true); - } - - ZigType *return_type = fn_type->data.fn.fn_type_id.return_type; - if (return_type->id == ZigTypeIdUnreachable) { - addLLVMFnAttr(llvm_fn, "noreturn"); - } - - if (!calling_convention_allows_zig_types(cc)) { - // A simplistic and desperate attempt at making the compiler respect the - // target ABI for return types. - // This is just enough to avoid miscompiling the test suite, it will be - // better in stage2. - ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : - return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : - nullptr; - - if (int_type != nullptr) { - const bool is_signed = int_type->data.integral.is_signed; - const uint32_t bit_width = int_type->data.integral.bit_count; - bool should_extend = false; - - // Rough equivalent of Clang's isPromotableIntegerType. - switch (bit_width) { - case 1: // bool - case 8: // {un,}signed char - case 16: // {un,}signed short - should_extend = true; - break; - default: - break; - } - - switch (g->zig_target->arch) { - case ZigLLVM_sparcv9: - case ZigLLVM_riscv64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - // Always extend to the register width. - should_extend = bit_width < 64; - break; - default: - break; - } - - // {zero,sign}-extend the result. - if (should_extend) { - if (is_signed) - addLLVMAttr(llvm_fn, 0, "signext"); - else - addLLVMAttr(llvm_fn, 0, "zeroext"); - } - } - } - - if (fn->body_node != nullptr) { - maybe_export_dll(g, llvm_fn, linkage); - - bool want_ssp_attrs = g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease && - g->link_libc && - // WASI-libc does not support stack-protector yet. - !target_is_wasm(g->zig_target); - if (want_ssp_attrs) { - addLLVMFnAttr(llvm_fn, "sspstrong"); - addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4"); - } - if (g->have_stack_probing && !fn->def_scope->safety_off) { - addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack"); - } else if (g->zig_target->os == OsUefi) { - addLLVMFnAttrStr(llvm_fn, "no-stack-arg-probe", ""); - } - } else { - maybe_import_dll(g, llvm_fn, linkage); - } - - if (fn->alignstack_value != 0) { - addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value); - } - - if (!g->omit_frame_pointer && cc != CallingConventionInline) { - ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all"); - } - if (fn->section_name) { - LLVMSetSection(llvm_fn, buf_ptr(fn->section_name)); - } - if (fn->align_bytes > 0) { - LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes); - } else { - // We'd like to set the best alignment for the function here, but on Darwin LLVM gives - // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling - // any of the functions for getting alignment. Not specifying the alignment should - // use the ABI alignment, which is fine. - } - - add_common_fn_attributes(g, llvm_fn); - - if (is_async) { - addLLVMArgAttr(llvm_fn, 0, "nonnull"); - } else { - unsigned init_gen_i = 0; - if (!type_has_bits(g, return_type)) { - // nothing to do - } else if (type_is_nonnull_ptr(g, return_type)) { - addLLVMAttr(llvm_fn, 0, "nonnull"); - } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { - // Sret pointers must not be address 0 - addLLVMArgAttr(llvm_fn, 0, "nonnull"); - ZigLLVMAddSretAttr(llvm_fn, get_llvm_type(g, return_type)); - if (cc_want_sret_attr(cc)) { - addLLVMArgAttr(llvm_fn, 0, "noalias"); - } - init_gen_i = 1; - } - - // set parameter attributes - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdAttrs; - fn_walk.data.attrs.fn = fn; - fn_walk.data.attrs.llvm_fn = llvm_fn; - fn_walk.data.attrs.gen_i = init_gen_i; - walk_function_params(g, fn_type, &fn_walk); - - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn); - if (err_ret_trace_arg_index != UINT32_MAX) { - // Error return trace memory is in the stack, which is impossible to be at address 0 - // on any architecture. - addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull"); - } - } - - return llvm_fn; -} - -static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) { - if (fn->llvm_value) - return fn->llvm_value; - - fn->llvm_value = make_fn_llvm_value(g, fn); - fn->llvm_name = strdup(LLVMGetValueName(fn->llvm_value)); - return fn->llvm_value; -} - -static uint32_t node_line_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].line + 1; -} - -static uint32_t node_column_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].column + 1; -} - -static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { - if (scope->di_scope) - return scope->di_scope; - - ZigType *import = get_scope_import(scope); - switch (scope->id) { - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdFnDef: - { - assert(scope->parent); - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - ZigFn *fn_table_entry = fn_scope->fn_entry; - if (!fn_table_entry->proto_node) - return get_di_scope(g, scope->parent); - unsigned line_number = node_line_onebased(fn_table_entry->proto_node); - unsigned scope_line = line_number; - bool is_definition = fn_table_entry->body_node != nullptr; - bool is_optimized = g->build_mode != BuildModeDebug; - bool is_internal_linkage = (fn_table_entry->body_node != nullptr && - fn_table_entry->export_list.length == 0); - unsigned flags = ZigLLVM_DIFlags_StaticMember; - ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent); - assert(fn_di_scope != nullptr); - assert(fn_table_entry->raw_di_type != nullptr); - ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, - fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", - import->data.structure.root_struct->di_file, line_number, - fn_table_entry->raw_di_type, is_internal_linkage, - is_definition, scope_line, flags, is_optimized, nullptr); - - scope->di_scope = ZigLLVMSubprogramToScope(subprogram); - if (!g->strip_debug_symbols) { - ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); - } - return scope->di_scope; - } - case ScopeIdDecls: - if (scope->parent) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - assert(decls_scope->container_type); - scope->di_scope = ZigLLVMTypeToScope(get_llvm_di_type(g, decls_scope->container_type)); - } else { - scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file); - } - return scope->di_scope; - case ScopeIdBlock: - case ScopeIdDefer: - { - assert(scope->parent); - ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, - get_di_scope(g, scope->parent), - import->data.structure.root_struct->di_file, - node_line_onebased(scope->source_node), - node_column_onebased(scope->source_node)); - scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); - return scope->di_scope; - } - case ScopeIdVarDecl: - case ScopeIdDeferExpr: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - return get_di_scope(g, scope->parent); - } - zig_unreachable(); -} - -static void clear_debug_source_node(CodeGen *g) { - ZigLLVMClearCurrentDebugLocation(g->builder); -} - -static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type, - const char *signed_name, const char *unsigned_name) -{ - ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - char fn_name[64]; - - assert(int_type->id == ZigTypeIdInt); - const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name; - - LLVMTypeRef param_types[] = { - get_llvm_type(g, operand_type), - get_llvm_type(g, operand_type), - }; - - if (operand_type->id == ZigTypeIdVector) { - snprintf(fn_name, sizeof(fn_name), "llvm.%s.with.overflow.v%" PRIu64 "i%" PRIu32, signed_str, - operand_type->data.vector.len, int_type->data.integral.bit_count); - - LLVMTypeRef return_elem_types[] = { - get_llvm_type(g, operand_type), - LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len), - }; - LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); - LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - return fn_val; - } else { - snprintf(fn_name, sizeof(fn_name), "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count); - - LLVMTypeRef return_elem_types[] = { - get_llvm_type(g, operand_type), - LLVMInt1Type(), - }; - LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); - LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - return fn_val; - } -} - -static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSubMul add_sub_mul) { - ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - assert(int_type->id == ZigTypeIdInt); - - ZigLLVMFnKey key = {}; - key.id = ZigLLVMFnIdOverflowArithmetic; - key.data.overflow_arithmetic.is_signed = int_type->data.integral.is_signed; - key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; - key.data.overflow_arithmetic.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.overflow_arithmetic.vector_len = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.len : 0; - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - LLVMValueRef fn_val; - switch (add_sub_mul) { - case AddSubMulAdd: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "sadd", "uadd"); - break; - case AddSubMulSub: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "ssub", "usub"); - break; - case AddSubMulMul: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "smul", "umul"); - break; - } - - g->llvm_fn_table.put(key, fn_val); - return fn_val; -} - -static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) { - assert(type_entry->id == ZigTypeIdFloat || - type_entry->id == ZigTypeIdVector); - - bool is_vector = (type_entry->id == ZigTypeIdVector); - ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry; - uint32_t float_bits = float_type->data.floating.bit_count; - - // LLVM incorrectly lowers the fma builtin for f128 to fmal, which is for - // `long double`. On some targets this will be correct; on others it will be incorrect. - if (fn_id == ZigLLVMFnIdFMA && float_bits == 128 && - !target_long_double_is_f128(g->zig_target)) - { - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, "fmaq"); - if (existing_llvm_fn != nullptr) return existing_llvm_fn; - - LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); - LLVMTypeRef return_elem_types[3] = { float_type_ref, float_type_ref, float_type_ref }; - LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, 3, false); - return LLVMAddFunction(g->module, "fmaq", fn_type); - } - - ZigLLVMFnKey key = {}; - key.id = fn_id; - key.data.floating.bit_count = float_bits; - key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; - key.data.floating.op = op; - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - const char *name; - uint32_t num_args; - if (fn_id == ZigLLVMFnIdFMA) { - name = "fma"; - num_args = 3; - } else if (fn_id == ZigLLVMFnIdFloatOp) { - name = float_un_op_to_name(op); - num_args = 1; - } else { - zig_unreachable(); - } - - char fn_name[64]; - if (is_vector) - snprintf(fn_name, sizeof(fn_name), "llvm.%s.v%" PRIu32 "f%" PRIu32, name, key.data.floating.vector_len, key.data.floating.bit_count); - else - snprintf(fn_name, sizeof(fn_name), "llvm.%s.f%" PRIu32, name, key.data.floating.bit_count); - LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); - LLVMTypeRef return_elem_types[3] = { float_type_ref, float_type_ref, float_type_ref }; - LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, num_args, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - - g->llvm_fn_table.put(key, fn_val); - return fn_val; -} - -static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, - uint32_t alignment, bool is_volatile) -{ - LLVMValueRef instruction = LLVMBuildStore(g->builder, value, ptr); - if (is_volatile) LLVMSetVolatile(instruction, true); - if (alignment != 0) { - LLVMSetAlignment(instruction, alignment); - } - return instruction; -} - -static LLVMValueRef gen_store(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, ZigType *ptr_type) { - assert(ptr_type->id == ZigTypeIdPointer); - uint32_t alignment = get_ptr_align(g, ptr_type); - return gen_store_untyped(g, value, ptr, alignment, ptr_type->data.pointer.is_volatile); -} - -static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMTypeRef elem_llvm_ty, LLVMValueRef ptr, - uint32_t alignment, bool is_volatile, const char *name) -{ - LLVMValueRef result = LLVMBuildLoad2(g->builder, elem_llvm_ty, ptr, name); - if (is_volatile) LLVMSetVolatile(result, true); - if (alignment != 0) { - LLVMSetAlignment(result, alignment); - } - return result; -} - -static LLVMValueRef gen_load(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, const char *name) { - assert(ptr_type->id == ZigTypeIdPointer); - uint32_t alignment = get_ptr_align(g, ptr_type); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_type->data.pointer.child_type); - bool is_volatile = ptr_type->data.pointer.is_volatile; - return gen_load_untyped(g, elem_llvm_ty, ptr, alignment, is_volatile, name); -} - -static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type, ZigType *ptr_type) { - if (type_has_bits(g, type)) { - if (handle_is_ptr(g, type)) { - return ptr; - } else { - assert(ptr_type->id == ZigTypeIdPointer); - return gen_load(g, ptr, ptr_type, ""); - } - } else { - return nullptr; - } -} - -static void ir_assert_impl(bool ok, Stage1AirInst *source_instruction, const char *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - -static bool ir_want_fast_math(CodeGen *g, Stage1AirInst *instruction) { - // TODO memoize - Scope *scope = instruction->scope; - while (scope) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - if (block_scope->fast_math_set_node) - return block_scope->fast_math_on; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - if (decls_scope->fast_math_set_node) - return decls_scope->fast_math_on; - } - scope = scope->parent; - } - return false; -} - -static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) { - // TODO memoize - while (scope) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - if (block_scope->safety_set_node) - return !block_scope->safety_off; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - if (decls_scope->safety_set_node) - return !decls_scope->safety_off; - } - scope = scope->parent; - } - - return (g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease); -} - -static bool ir_want_runtime_safety(CodeGen *g, Stage1AirInst *instruction) { - return ir_want_runtime_safety_scope(g, instruction->scope); -} - -static Buf *panic_msg_buf(PanicMsgId msg_id) { - switch (msg_id) { - case PanicMsgIdCount: - zig_unreachable(); - case PanicMsgIdBoundsCheckFailure: - return buf_create_from_str("index out of bounds"); - case PanicMsgIdCastNegativeToUnsigned: - return buf_create_from_str("attempt to cast negative value to unsigned integer"); - case PanicMsgIdCastTruncatedData: - return buf_create_from_str("integer cast truncated bits"); - case PanicMsgIdIntegerOverflow: - return buf_create_from_str("integer overflow"); - case PanicMsgIdShlOverflowedBits: - return buf_create_from_str("left shift overflowed bits"); - case PanicMsgIdShrOverflowedBits: - return buf_create_from_str("right shift overflowed bits"); - case PanicMsgIdDivisionByZero: - return buf_create_from_str("division by zero"); - case PanicMsgIdRemainderDivisionByZero: - return buf_create_from_str("remainder division by zero or negative value"); - case PanicMsgIdExactDivisionRemainder: - return buf_create_from_str("exact division produced remainder"); - case PanicMsgIdUnwrapOptionalFail: - return buf_create_from_str("attempt to use null value"); - case PanicMsgIdUnreachable: - return buf_create_from_str("reached unreachable code"); - case PanicMsgIdInvalidErrorCode: - return buf_create_from_str("invalid error code"); - case PanicMsgIdIncorrectAlignment: - return buf_create_from_str("incorrect alignment"); - case PanicMsgIdBadUnionField: - return buf_create_from_str("access of inactive union field"); - case PanicMsgIdBadEnumValue: - return buf_create_from_str("invalid enum value"); - case PanicMsgIdFloatToInt: - return buf_create_from_str("integer part of floating point value out of bounds"); - case PanicMsgIdPtrCastNull: - return buf_create_from_str("cast causes pointer to be null"); - case PanicMsgIdBadResume: - return buf_create_from_str("resumed an async function which already returned"); - case PanicMsgIdBadAwait: - return buf_create_from_str("async function awaited twice"); - case PanicMsgIdBadReturn: - return buf_create_from_str("async function returned twice"); - case PanicMsgIdResumedAnAwaitingFn: - return buf_create_from_str("awaiting function resumed"); - case PanicMsgIdFrameTooSmall: - return buf_create_from_str("frame too small"); - case PanicMsgIdResumedFnPendingAwait: - return buf_create_from_str("resumed an async function which can only be awaited"); - case PanicMsgIdBadNoSuspendCall: - return buf_create_from_str("async function called in nosuspend scope suspended"); - case PanicMsgIdResumeNotSuspendedFn: - return buf_create_from_str("resumed a non-suspended function"); - case PanicMsgIdBadSentinel: - return buf_create_from_str("sentinel mismatch"); - case PanicMsgIdShxTooBigRhs: - return buf_create_from_str("shift amount is greater than the type size"); - } - zig_unreachable(); -} - -static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { - ZigValue *val = &g->panic_msg_vals[msg_id]; - if (!val->llvm_global) { - - Buf *buf_msg = panic_msg_buf(msg_id); - ZigValue *array_val = create_const_str_lit(g, buf_msg)->data.x_ptr.data.ref.pointee; - init_const_slice(g, val, array_val, 0, buf_len(buf_msg), true, nullptr); - - render_const_val(g, val, ""); - render_const_val_global(g, val, ""); - - assert(val->llvm_global); - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - return LLVMConstBitCast(val->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0)); -} - -static ZigType *ptr_to_stack_trace_type(CodeGen *g) { - return get_pointer_to_type(g, get_stack_trace_type(g), false); -} - -static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg, - bool stack_trace_is_llvm_alloca) -{ - assert(g->panic_fn != nullptr); - LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); - ZigLLVM_CallingConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); - if (stack_trace_arg == nullptr) { - stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - LLVMValueRef null_ret_alloc; - { - ZigValue null_val = {}; - null_val.special = ConstValSpecialStatic; - null_val.data.x_optional = nullptr; - null_val.type = get_optional_type2(g, g->builtin_types.entry_usize); - LLVMValueRef null_ret_val = gen_const_val(g, &null_val, ""); - null_ret_alloc = build_alloca(g, null_val.type, "ret_addr", 0); - LLVMBuildStore(g->builder, null_ret_val, null_ret_alloc); - } - - LLVMValueRef args[] = { - msg_arg, - stack_trace_arg, - null_ret_alloc, - }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, args, 3, llvm_cc, ZigLLVM_CallAttrAuto, ""); - if (!stack_trace_is_llvm_alloca) { - // The stack trace argument is not in the stack of the caller, so - // we'd like to set tail call here, but because slices (the type of msg_arg) are - // still passed as pointers (see https://github.com/ziglang/zig/issues/561) we still - // cannot make this a tail call. - //LLVMSetTailCall(call_instruction, true); - } - LLVMBuildUnreachable(g->builder); -} - -// TODO update most callsites to call gen_assertion instead of this -static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) { - gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr, false); -} - -static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) { - if (ir_want_runtime_safety_scope(g, source_scope)) { - gen_safety_crash(g, msg_id); - } else { - LLVMBuildUnreachable(g->builder); - } -} - -static void gen_assertion(CodeGen *g, PanicMsgId msg_id, Stage1AirInst *source_instruction) { - return gen_assertion_scope(g, msg_id, source_instruction->scope); -} - -static LLVMValueRef gen_wasm_memory_size(CodeGen *g) { - if (g->wasm_memory_size) - return g->wasm_memory_size; - - // TODO adjust for wasm64 as well - // declare i32 @llvm.wasm.memory.size.i32(i32) nounwind readonly - LLVMTypeRef param_type = LLVMInt32Type(); - LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), ¶m_type, 1, false); - g->wasm_memory_size = LLVMAddFunction(g->module, "llvm.wasm.memory.size.i32", fn_type); - assert(LLVMGetIntrinsicID(g->wasm_memory_size)); - - return g->wasm_memory_size; -} - -static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) { - if (g->wasm_memory_grow) - return g->wasm_memory_grow; - - // TODO adjust for wasm64 as well - // declare i32 @llvm.wasm.memory.grow.i32(i32, i32) nounwind - LLVMTypeRef param_types[] = { - LLVMInt32Type(), - LLVMInt32Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, false); - g->wasm_memory_grow = LLVMAddFunction(g->module, "llvm.wasm.memory.grow.i32", fn_type); - assert(LLVMGetIntrinsicID(g->wasm_memory_grow)); - - return g->wasm_memory_grow; -} - -static LLVMValueRef gen_prefetch(CodeGen *g) { - if (g->prefetch) - return g->prefetch; - - // declare void @llvm.prefetch(i8*, i32, i32, i32) - LLVMTypeRef param_types[] = { - LLVMPointerType(LLVMInt8Type(), 0), - LLVMInt32Type(), - LLVMInt32Type(), - LLVMInt32Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 4, false); - g->prefetch = LLVMAddFunction(g->module, "llvm.prefetch.p0", fn_type); - assert(LLVMGetIntrinsicID(g->prefetch)); - - return g->prefetch; -} - -static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { - if (g->stacksave_fn_val) - return g->stacksave_fn_val; - - // declare i8* @llvm.stacksave() - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false); - g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type); - assert(LLVMGetIntrinsicID(g->stacksave_fn_val)); - - return g->stacksave_fn_val; -} - -static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) { - if (g->stackrestore_fn_val) - return g->stackrestore_fn_val; - - // declare void @llvm.stackrestore(i8* %ptr) - - LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0); - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), ¶m_type, 1, false); - g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type); - assert(LLVMGetIntrinsicID(g->stackrestore_fn_val)); - - return g->stackrestore_fn_val; -} - -static LLVMValueRef get_write_register_fn_val(CodeGen *g) { - if (g->write_register_fn_val) - return g->write_register_fn_val; - - // declare void @llvm.write_register.i64(metadata, i64 @value) - // !0 = !{!"sp\00"} - - LLVMTypeRef param_types[] = { - LLVMMetadataTypeInContext(LLVMGetGlobalContext()), - LLVMIntType(g->pointer_size_bytes * 8), - }; - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); - Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8); - g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); - assert(LLVMGetIntrinsicID(g->write_register_fn_val)); - - return g->write_register_fn_val; -} - -static LLVMValueRef get_return_address_fn_val(CodeGen *g) { - if (g->return_address_fn_val) - return g->return_address_fn_val; - - ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type), - &g->builtin_types.entry_i32->llvm_type, 1, false); - g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); - assert(LLVMGetIntrinsicID(g->return_address_fn_val)); - - return g->return_address_fn_val; -} - -static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { - if (g->add_error_return_trace_addr_fn_val != nullptr) - return g->add_error_return_trace_addr_fn_val; - - LLVMTypeRef arg_types[] = { - get_llvm_type(g, ptr_to_stack_trace_type(g)), - g->builtin_types.entry_usize->llvm_type, - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); - - const char *fn_name = get_mangled_name(g, "__zig_add_err_ret_trace_addr"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "alwaysinline"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - // Error return trace memory is in the stack, which is impossible to be at address 0 - // on any architecture. - addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - // stack_trace.instruction_addresses[stack_trace.index & (stack_trace.instruction_addresses.len - 1)] = return_address; - - LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); - LLVMValueRef address_value = LLVMGetParam(fn_val, 1); - - size_t index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - LLVMValueRef index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - err_ret_trace_ptr, (unsigned)index_field_index, ""); - size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - err_ret_trace_ptr, (unsigned)addresses_field_index, ""); - - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)ptr_field_index, ""); - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)len_field_index, ""); - - LLVMValueRef len_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - LLVMValueRef index_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(index_field_ptr), - index_field_ptr, 0, false, ""); - LLVMValueRef len_val_minus_one = LLVMBuildSub(g->builder, len_value, LLVMConstInt(usize_type_ref, 1, false), ""); - LLVMValueRef masked_val = LLVMBuildAnd(g->builder, index_val, len_val_minus_one, ""); - LLVMValueRef address_indices[] = { - masked_val, - }; - - LLVMValueRef ptr_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - LLVMValueRef address_slot = LLVMBuildInBoundsGEP2(g->builder, usize_type_ref, ptr_value, address_indices, 1, ""); - - gen_store_untyped(g, address_value, address_slot, 0, false); - - // stack_trace.index += 1; - LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); - gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); - - // return; - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->add_error_return_trace_addr_fn_val = fn_val; - return fn_val; -} - -static LLVMValueRef get_return_err_fn(CodeGen *g) { - if (g->return_err_fn != nullptr) - return g->return_err_fn; - - assert(g->err_tag_type != nullptr); - - LLVMTypeRef arg_types[] = { - // error return trace pointer - get_llvm_type(g, ptr_to_stack_trace_type(g)), - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); - - const char *fn_name = get_mangled_name(g, "__zig_return_error"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address - addLLVMFnAttr(fn_val, "cold"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - // this is above the ZigLLVMClearCurrentDebugLocation - LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_i32)); - LLVMValueRef return_address_ptr = LLVMBuildCall2(g->builder, - LLVMGlobalGetValueType(get_return_address_fn_val(g)), get_return_address_fn_val(g), &zero, 1, ""); - LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); - - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); - LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull"); - - LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_ret_trace_ptr, - LLVMConstNull(LLVMTypeOf(err_ret_trace_ptr)), ""); - LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block); - LLVMValueRef args[] = { err_ret_trace_ptr, return_address }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(add_error_return_trace_addr_fn_val), - add_error_return_trace_addr_fn_val, args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->return_err_fn = fn_val; - return fn_val; -} - -static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { - if (g->safety_crash_err_fn != nullptr) - return g->safety_crash_err_fn; - - static const char *unwrap_err_msg_text = "attempt to unwrap error: "; - - g->generate_error_name_table = true; - generate_error_name_table(g); - assert(g->err_name_table != nullptr); - - // Generate the constant part of the error message - LLVMValueRef msg_prefix_init = LLVMConstString(unwrap_err_msg_text, strlen(unwrap_err_msg_text), 1); - LLVMValueRef msg_prefix = LLVMAddGlobal(g->module, LLVMTypeOf(msg_prefix_init), ""); - LLVMSetInitializer(msg_prefix, msg_prefix_init); - LLVMSetLinkage(msg_prefix, LLVMPrivateLinkage); - LLVMSetGlobalConstant(msg_prefix, true); - - const char *fn_name = get_mangled_name(g, "__zig_fail_unwrap"); - LLVMTypeRef fn_type_ref; - if (g->have_err_ret_tracing) { - LLVMTypeRef arg_types[] = { - get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)), - get_llvm_type(g, g->err_tag_type), - }; - fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); - } else { - LLVMTypeRef arg_types[] = { - get_llvm_type(g, g->err_tag_type), - }; - fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); - } - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "noreturn"); - addLLVMFnAttr(fn_val, "cold"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - // Not setting alignment here. See the comment above about - // "Cannot getTypeInfo() on a type that is unsized!" - // assertion failure on Darwin. - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - ZigType *usize_ty = g->builtin_types.entry_usize; - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - - // Allocate a buffer to hold the fully-formatted error message - const size_t err_buf_len = strlen(unwrap_err_msg_text) + g->largest_err_name_len; - LLVMValueRef max_msg_len = LLVMConstInt(usize_ty->llvm_type, err_buf_len, 0); - LLVMValueRef msg_buffer = LLVMBuildArrayAlloca(g->builder, LLVMInt8Type(), max_msg_len, "msg_buffer"); - - // Allocate a []u8 slice for the message - LLVMValueRef msg_slice = build_alloca(g, str_type, "msg_slice", 0); - - LLVMValueRef err_ret_trace_arg; - LLVMValueRef err_val; - if (g->have_err_ret_tracing) { - err_ret_trace_arg = LLVMGetParam(fn_val, 0); - err_val = LLVMGetParam(fn_val, 1); - } else { - err_ret_trace_arg = nullptr; - err_val = LLVMGetParam(fn_val, 0); - } - - // Fetch the error name from the global table - LLVMValueRef err_table_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - err_val, - }; - LLVMValueRef err_name_val = LLVMBuildInBoundsGEP2(g->builder, - LLVMGlobalGetValueType(g->err_name_table), - g->err_name_table, err_table_indices, 2, ""); - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(err_name_val), err_name_val, slice_ptr_index, ""); - LLVMValueRef err_name_ptr = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(err_name_val), err_name_val, slice_len_index, ""); - LLVMValueRef err_name_len = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - - LLVMValueRef msg_prefix_len = LLVMConstInt(usize_ty->llvm_type, strlen(unwrap_err_msg_text), false); - // Points to the beginning of msg_buffer - LLVMValueRef msg_buffer_ptr_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - }; - LLVMValueRef msg_buffer_ptr = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), msg_buffer, - msg_buffer_ptr_indices, 1, ""); - // Points to the beginning of the constant prefix message - LLVMValueRef msg_prefix_ptr_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - }; - LLVMValueRef msg_prefix_ptr = LLVMConstInBoundsGEP2(LLVMInt8Type(), msg_prefix, msg_prefix_ptr_indices, 1); - - // Build the message using the prefix... - ZigLLVMBuildMemCpy(g->builder, msg_buffer_ptr, 1, msg_prefix_ptr, 1, msg_prefix_len, false); - // ..and append the error name - LLVMValueRef msg_buffer_ptr_after_indices[] = { - msg_prefix_len, - }; - LLVMValueRef msg_buffer_ptr_after = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), msg_buffer, msg_buffer_ptr_after_indices, 1, ""); - ZigLLVMBuildMemCpy(g->builder, msg_buffer_ptr_after, 1, err_name_ptr, 1, err_name_len, false); - - // Set the slice pointer - LLVMValueRef msg_slice_ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, str_type), msg_slice, slice_ptr_index, ""); - gen_store_untyped(g, msg_buffer_ptr, msg_slice_ptr_field_ptr, 0, false); - - // Set the slice length - LLVMValueRef slice_len = LLVMBuildNUWAdd(g->builder, msg_prefix_len, err_name_len, ""); - LLVMValueRef msg_slice_len_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, str_type), msg_slice, slice_len_index, ""); - gen_store_untyped(g, slice_len, msg_slice_len_field_ptr, 0, false); - - // Call panic() - gen_panic(g, msg_slice, err_ret_trace_arg, false); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->safety_crash_err_fn = fn_val; - return fn_val; -} - -static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope, bool *is_llvm_alloca) { - if (!g->have_err_ret_tracing) { - *is_llvm_alloca = false; - return nullptr; - } - if (g->cur_err_ret_trace_val_stack != nullptr) { - *is_llvm_alloca = !fn_is_async(g->cur_fn); - return g->cur_err_ret_trace_val_stack; - } - *is_llvm_alloca = false; - return g->cur_err_ret_trace_val_arg; -} - -static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { - LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - LLVMValueRef call_instruction; - bool is_llvm_alloca = false; - if (g->have_err_ret_tracing) { - LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope, &is_llvm_alloca); - if (err_ret_trace_val == nullptr) { - err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - LLVMValueRef args[] = { - err_ret_trace_val, - err_val, - }; - call_instruction = ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(safety_crash_err_fn), - safety_crash_err_fn, args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } else { - LLVMValueRef args[] = { - err_val, - }; - call_instruction = ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(safety_crash_err_fn), - safety_crash_err_fn, args, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - if (!is_llvm_alloca) { - LLVMSetTailCall(call_instruction, true); - } - LLVMBuildUnreachable(g->builder); -} - -static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, - LLVMIntPredicate lower_pred, LLVMValueRef lower_value, - LLVMIntPredicate upper_pred, LLVMValueRef upper_value) -{ - if (!lower_value && !upper_value) { - return; - } - if (upper_value && !lower_value) { - lower_value = upper_value; - lower_pred = upper_pred; - upper_value = nullptr; - } - - LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk"); - LLVMBasicBlockRef lower_ok_block = upper_value ? - LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block; - - LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, ""); - LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); - - LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block); - gen_safety_crash(g, PanicMsgIdBoundsCheckFailure); - - if (upper_value) { - LLVMPositionBuilderAtEnd(g->builder, lower_ok_block); - LLVMValueRef upper_ok_val = LLVMBuildICmp(g->builder, upper_pred, target_val, upper_value, ""); - LLVMBuildCondBr(g->builder, upper_ok_val, ok_block, bounds_check_fail_block); - } - - LLVMPositionBuilderAtEnd(g->builder, ok_block); -} - -static void add_sentinel_check(CodeGen *g, LLVMValueRef sentinel_elem_ptr, ZigValue *sentinel) { - LLVMValueRef expected_sentinel = gen_const_val(g, sentinel, ""); - - LLVMValueRef actual_sentinel = gen_load_untyped(g, LLVMTypeOf(expected_sentinel), sentinel_elem_ptr, 0, false, ""); - LLVMValueRef ok_bit; - if (sentinel->type->id == ZigTypeIdFloat) { - ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, actual_sentinel, expected_sentinel, ""); - } else { - ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, actual_sentinel, expected_sentinel, ""); - } - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SentinelFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SentinelOk"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdBadSentinel); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); -} - -static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); - if (int_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return nullptr; -} - -static const char *get_compiler_rt_type_abbrev(ZigType *type) { - uint16_t bits; - if (type->id == ZigTypeIdFloat) { - bits = type->data.floating.bit_count; - } else if (type->id == ZigTypeIdInt) { - bits = type->data.integral.bit_count; - } else { - zig_unreachable(); - } - switch (bits) { - case 16: - return "h"; - case 32: - return "s"; - case 64: - return "d"; - case 80: - return "x"; - case 128: - return "t"; - default: - zig_unreachable(); - } -} - -static const char *libc_float_prefix(CodeGen *g, ZigType *float_type) { - switch (float_type->data.floating.bit_count) { - case 16: - case 80: - return "__"; - case 32: - case 64: - case 128: - return ""; - default: - zig_unreachable(); - } -} - -static const char *libc_float_suffix(CodeGen *g, ZigType *float_type) { - switch (float_type->size_in_bits) { - case 16: return "h"; // Non-standard - case 32: return "f"; - case 64: return ""; - case 80: return "x"; // Non-standard - case 128: return "q"; // Non-standard - default: zig_unreachable(); - } -} - -static LLVMValueRef gen_soft_float_widen_or_shorten(CodeGen *g, ZigType *actual_type, - ZigType *wanted_type, LLVMValueRef expr_val) -{ - ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? - actual_type->data.vector.elem_type : actual_type; - ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - uint64_t actual_bits = scalar_actual_type->data.floating.bit_count; - uint64_t wanted_bits = scalar_wanted_type->data.floating.bit_count; - - if (actual_bits == wanted_bits) - return expr_val; - - LLVMValueRef result; - bool castTruncatedToF16 = false; - - char fn_name[64]; - if (wanted_bits < actual_bits) { - snprintf(fn_name, sizeof(fn_name), "__trunc%sf%sf2", - get_compiler_rt_type_abbrev(scalar_actual_type), - get_compiler_rt_type_abbrev(scalar_wanted_type)); - } else { - snprintf(fn_name, sizeof(fn_name), "__extend%sf%sf2", - get_compiler_rt_type_abbrev(scalar_actual_type), - get_compiler_rt_type_abbrev(scalar_wanted_type)); - } - - LLVMTypeRef return_type = scalar_wanted_type->llvm_type; - LLVMTypeRef param_type = scalar_actual_type->llvm_type; - - if (!target_is_arm(g->zig_target)) { - // Only Arm has a native f16 type, other platforms soft-implement it using u16 instead. - if (scalar_wanted_type == g->builtin_types.entry_f16) { - return_type = g->builtin_types.entry_u16->llvm_type; - castTruncatedToF16 = true; - } - if (scalar_actual_type == g->builtin_types.entry_f16) { - param_type = g->builtin_types.entry_u16->llvm_type; - expr_val = LLVMBuildBitCast(g->builder, expr_val, param_type, ""); - } - } - - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type); - result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, ""); - - // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f16 - if (castTruncatedToF16) { - result = LLVMBuildBitCast(g->builder, result, g->builtin_types.entry_f16->llvm_type, ""); - } - - return result; -} - -static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, - ZigType *wanted_type, LLVMValueRef expr_val) -{ - assert(actual_type->id == wanted_type->id); - - ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? - actual_type->data.vector.elem_type : actual_type; - ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - - uint64_t actual_bits; - uint64_t wanted_bits; - if (scalar_actual_type->id == ZigTypeIdFloat) { - - if (((scalar_actual_type == g->builtin_types.entry_f80 - || scalar_wanted_type == g->builtin_types.entry_f80) - && !target_has_f80(g->zig_target)) || - ((scalar_actual_type == g->builtin_types.entry_f16 - || scalar_wanted_type == g->builtin_types.entry_f16) - && !target_is_arm(g->zig_target))) - { - return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val); - } - actual_bits = scalar_actual_type->data.floating.bit_count; - wanted_bits = scalar_wanted_type->data.floating.bit_count; - } else if (scalar_actual_type->id == ZigTypeIdInt) { - actual_bits = scalar_actual_type->data.integral.bit_count; - wanted_bits = scalar_wanted_type->data.integral.bit_count; - } else { - zig_unreachable(); - } - - if (expr_val == nullptr) { - if (scalar_actual_type->id == ZigTypeIdInt && actual_bits == 0) { - if (wanted_bits == 0) { - return expr_val; - } else { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, wanted_type)); - return zero; - } - } else { - zig_unreachable(); - } - } - - if (scalar_actual_type->id == ZigTypeIdInt && want_runtime_safety && ( - // negative to unsigned - (!scalar_wanted_type->data.integral.is_signed && scalar_actual_type->data.integral.is_signed) || - // unsigned would become negative - (scalar_wanted_type->data.integral.is_signed && !scalar_actual_type->data.integral.is_signed && actual_bits == wanted_bits))) - { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, actual_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail"); - if (actual_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, scalar_actual_type->data.integral.is_signed ? PanicMsgIdCastNegativeToUnsigned : PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (actual_bits == wanted_bits) { - return expr_val; - } else if (actual_bits < wanted_bits) { - if (scalar_actual_type->id == ZigTypeIdFloat) { - return LLVMBuildFPExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (scalar_actual_type->id == ZigTypeIdInt) { - if (scalar_actual_type->data.integral.is_signed) { - return LLVMBuildSExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } else { - zig_unreachable(); - } - } else if (actual_bits > wanted_bits) { - if (scalar_actual_type->id == ZigTypeIdFloat) { - return LLVMBuildFPTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (scalar_actual_type->id == ZigTypeIdInt) { - if (wanted_bits == 0) { - if (!want_runtime_safety) - return nullptr; - - return gen_assert_zero(g, expr_val, actual_type); - } - LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - if (!want_runtime_safety) { - return trunc_val; - } - LLVMValueRef orig_val; - if (scalar_wanted_type->data.integral.is_signed) { - orig_val = LLVMBuildSExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); - } else { - orig_val = LLVMBuildZExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); - } - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, ""); - if (actual_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return trunc_val; - } else { - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); -// These are lookup table using the AddSubMul enum as the lookup. -// If AddSubMul ever changes, then these tables will be out of -// date. -static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; -static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; -static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; -static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; - -static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, - LLVMValueRef val1, LLVMValueRef val2) -{ - LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); - LLVMValueRef params[] = { - val1, - val2, - }; - LLVMValueRef result_struct = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - if (operand_type->id == ZigTypeIdVector) { - overflow_bit = ZigLLVMBuildOrReduce(g->builder, overflow_bit); - } - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdIntegerOverflow); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { - switch (cmp_op) { - case IrBinOpCmpEq: - return LLVMIntEQ; - case IrBinOpCmpNotEq: - return LLVMIntNE; - case IrBinOpCmpLessThan: - return is_signed ? LLVMIntSLT : LLVMIntULT; - case IrBinOpCmpGreaterThan: - return is_signed ? LLVMIntSGT : LLVMIntUGT; - case IrBinOpCmpLessOrEq: - return is_signed ? LLVMIntSLE : LLVMIntULE; - case IrBinOpCmpGreaterOrEq: - return is_signed ? LLVMIntSGE : LLVMIntUGE; - default: - zig_unreachable(); - } -} - -static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { - switch (cmp_op) { - case IrBinOpCmpEq: - return LLVMRealOEQ; - case IrBinOpCmpNotEq: - return LLVMRealUNE; - case IrBinOpCmpLessThan: - return LLVMRealOLT; - case IrBinOpCmpGreaterThan: - return LLVMRealOGT; - case IrBinOpCmpLessOrEq: - return LLVMRealOLE; - case IrBinOpCmpGreaterOrEq: - return LLVMRealOGE; - default: - zig_unreachable(); - } -} - -static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, - LLVMValueRef value) -{ - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = ptr_type->data.pointer.child_type; - - if (!type_has_bits(g, child_type)) - return; - - if (handle_is_ptr(g, child_type)) { - assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind); - assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - - LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, value, ptr_u8, ""); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); - - ZigType *usize = g->builtin_types.entry_usize; - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, child_type)); - uint64_t src_align_bytes = get_abi_alignment(g, child_type); - uint64_t dest_align_bytes = get_ptr_align(g, ptr_type); - assert(size_bytes > 0); - assert(src_align_bytes > 0); - assert(dest_align_bytes > 0); - - ZigLLVMBuildMemCpy(g->builder, dest_ptr, dest_align_bytes, src_ptr, src_align_bytes, - LLVMConstInt(usize->llvm_type, size_bytes, false), - ptr_type->data.pointer.is_volatile); - return; - } - - assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME); - if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), - ptr_type->data.pointer.vector_index, false); - uint32_t vec_len = ptr_type->data.pointer.host_int_bytes; - LLVMTypeRef vec_llvm_ty = LLVMVectorType(get_llvm_type(g, ptr_type->data.pointer.child_type), vec_len); - LLVMValueRef loaded_vector = gen_load_untyped(g, vec_llvm_ty, ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - LLVMValueRef new_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, - index_val, ""); - gen_store(g, new_vector, ptr, ptr_type); - return; - } - - uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes == 0) { - gen_store(g, value, ptr, ptr_type); - return; - } - - bool big_endian = g->is_big_endian; - - LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); - LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); - LLVMValueRef containing_int = gen_load_untyped(g, LLVMIntType(host_int_bytes * 8), int_ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); - assert(host_bit_count == host_int_bytes * 8); - uint32_t size_in_bits = type_size_bits(g, child_type); - - uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host; - uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset; - LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); - - // Convert to equally-sized integer type in order to perform the bit - // operations on the value to store - LLVMTypeRef value_bits_type = LLVMIntType(size_in_bits); - LLVMValueRef value_bits = LLVMBuildBitCast(g->builder, value, value_bits_type, ""); - - LLVMValueRef mask_val = LLVMConstAllOnes(value_bits_type); - mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int)); - mask_val = LLVMConstShl(mask_val, shift_amt_val); - mask_val = LLVMConstNot(mask_val); - - LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, ""); - LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value_bits, LLVMTypeOf(containing_int), ""); - LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, ""); - LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, ""); - - gen_store(g, ored_value, int_ptr, ptr_type); -} - -static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { - if (g->strip_debug_symbols) return; - assert(var->di_loc_var != nullptr); - AstNode *source_node = var->decl_node; - ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(node_line_onebased(source_node), - node_column_onebased(source_node), get_di_scope(g, var->parent_scope)); - ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, - LLVMGetInsertBlock(g->builder)); -} - -static LLVMValueRef ir_llvm_value(CodeGen *g, Stage1AirInst *instruction) { - Error err; - - bool value_has_bits; - if ((err = type_has_bits2(g, instruction->value->type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (!value_has_bits) - return nullptr; - - if (!instruction->llvm_value) { - if (instruction->id == Stage1AirInstIdAwait) { - Stage1AirInstAwait *await = reinterpret_cast(instruction); - if (await->result_loc != nullptr) { - return get_handle_value(g, ir_llvm_value(g, await->result_loc), - await->result_loc->value->type->data.pointer.child_type, await->result_loc->value->type); - } - } - if (instruction->spill != nullptr) { - ZigType *ptr_type = instruction->spill->value->type; - ir_assert(ptr_type->id == ZigTypeIdPointer, instruction); - return get_handle_value(g, ir_llvm_value(g, instruction->spill), - ptr_type->data.pointer.child_type, instruction->spill->value->type); - } - ir_assert(instruction->value->special != ConstValSpecialRuntime, instruction); - assert(instruction->value->type); - render_const_val(g, instruction->value, ""); - // we might have to do some pointer casting here due to the way union - // values are rendered with a type other than the one we expect - if (handle_is_ptr(g, instruction->value->type)) { - render_const_val_global(g, instruction->value, ""); - ZigType *ptr_type = get_pointer_to_type(g, instruction->value->type, true); - instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value->llvm_global, get_llvm_type(g, ptr_type), ""); - } else { - instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value->llvm_value, - get_llvm_type(g, instruction->value->type), ""); - } - assert(instruction->llvm_value); - } - return instruction->llvm_value; -} - -void codegen_report_errors_and_exit(CodeGen *g) { - // Clear progress indicator before printing errors - if (g->sub_progress_node != nullptr) { - stage2_progress_end(g->sub_progress_node); - g->sub_progress_node = nullptr; - } - if (g->main_progress_node != nullptr) { - stage2_progress_end(g->main_progress_node); - g->main_progress_node = nullptr; - } - - assert(g->errors.length != 0); - for (size_t i = 0; i < g->errors.length; i += 1) { - ErrorMsg *err = g->errors.at(i); - print_err_msg(err, g->err_color); - } - exit(1); -} - -static void report_errors_and_maybe_exit(CodeGen *g) { - if (g->errors.length != 0) { - codegen_report_errors_and_exit(g); - } -} - -ATTRIBUTE_NORETURN -static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { - ErrorMsg *msg = add_node_error(g, source_node, - buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481")); - add_error_note(g, msg, source_node, - buf_sprintf("pointers, integers, floats, bools, and enums work on all targets")); - codegen_report_errors_and_exit(g); -} - -static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { - LLVMValueRef result = LLVMBuildAlloca(g->builder, get_llvm_type(g, type_entry), name); - LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment); - return result; -} - -static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { - // Initialized from the type for some walks, but because of C var args, - // initialized based on callsite instructions for that one. - FnTypeParamInfo *param_info = nullptr; - ZigType *ty; - ZigType *dest_ty = nullptr; - AstNode *source_node = nullptr; - LLVMValueRef val; - LLVMValueRef llvm_fn; - unsigned di_arg_index; - ZigVar *var; - switch (fn_walk->id) { - case FnWalkIdAttrs: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - source_node = fn_walk->data.attrs.fn->proto_node; - llvm_fn = fn_walk->data.attrs.llvm_fn; - break; - case FnWalkIdCall: { - if (src_i >= fn_walk->data.call.inst->arg_count) - return false; - Stage1AirInst *arg = fn_walk->data.call.inst->args[src_i]; - ty = arg->value->type; - source_node = arg->source_node; - val = ir_llvm_value(g, arg); - break; - } - case FnWalkIdTypes: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - break; - case FnWalkIdVars: - assert(src_i < fn_type->data.fn.fn_type_id.param_count); - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - var = fn_walk->data.vars.var; - source_node = var->decl_node; - llvm_fn = fn_walk->data.vars.llvm_fn; - break; - case FnWalkIdInits: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - var = fn_walk->data.inits.fn->variable_list.at(src_i); - source_node = fn_walk->data.inits.fn->proto_node; - llvm_fn = fn_walk->data.inits.llvm_fn; - break; - } - - if (type_is_c_abi_int_bail(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector || - ty->id == ZigTypeIdInt // TODO investigate if we need to change this - ) { - switch (fn_walk->id) { - case FnWalkIdAttrs: { - ZigType *ptr_type = get_codegen_ptr_type_bail(g, ty); - if (ptr_type != nullptr) { - if (type_is_nonnull_ptr(g, ty)) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - } - if (ptr_type->id == ZigTypeIdPointer && ptr_type->data.pointer.is_const) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly"); - } - if (param_info->is_noalias) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias"); - } - } - fn_walk->data.attrs.gen_i += 1; - break; - } - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, ty)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, ty)); - break; - case FnWalkIdVars: { - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - di_arg_index = fn_walk->data.vars.gen_i; - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: - clear_debug_source_node(g); - gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false); - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } - - { - // Arrays are just pointers - if (ty->id == ZigTypeIdArray) { - assert(handle_is_ptr(g, ty)); - switch (fn_walk->id) { - case FnWalkIdAttrs: - // arrays passed to C ABI functions may not be at address 0 - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: { - ZigType *gen_type = get_pointer_to_type(g, ty, true); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); - di_arg_index = fn_walk->data.vars.gen_i; - dest_ty = get_pointer_to_type(g, ty, false); - fn_walk->data.vars.gen_i += 1; - goto var_ok; - } - case FnWalkIdInits: - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } - - X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty); - size_t ty_size = type_size(g, ty); - if (abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval) { - assert(handle_is_ptr(g, ty)); - switch (fn_walk->id) { - case FnWalkIdAttrs: - if (abi_class != X64CABIClass_MEMORY_nobyval) { - ZigLLVMAddByValAttr(llvm_fn, fn_walk->data.attrs.gen_i, get_llvm_type(g, ty)); - addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); - } else if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) - { - // no attrs needed - } else { - if (source_node != nullptr) { - give_up_with_c_abi_error(g, source_node); - } - // otherwise allow codegen code to report a compile error - return false; - } - - // Byvalue parameters must not have address 0 - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: { - ZigType *gen_type = get_pointer_to_type(g, ty, true); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - di_arg_index = fn_walk->data.vars.gen_i; - var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); - dest_ty = get_pointer_to_type(g, ty, false); - fn_walk->data.vars.gen_i += 1; - goto var_ok; - } - case FnWalkIdInits: - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } else if (abi_class == X64CABIClass_INTEGER) { - switch (fn_walk->id) { - case FnWalkIdAttrs: - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: { - LLVMTypeRef int_type_ref = LLVMIntType((unsigned)ty_size * 8); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, LLVMPointerType(int_type_ref, 0), ""); - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, int_type_ref, bitcasted, ""); - fn_walk->data.call.gen_param_values->append(loaded); - break; - } - case FnWalkIdTypes: { - ZigType *gen_type = get_int_type(g, false, ty_size * 8); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - di_arg_index = fn_walk->data.vars.gen_i; - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: { - clear_debug_source_node(g); - if (!fn_is_async(fn_walk->data.inits.fn)) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); - LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); - gen_store_untyped(g, arg, bitcasted, var->align_bytes, false); - } - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - } - return true; - } else if (abi_class == X64CABIClass_AGG) { - // The SystemV ABI says that we have to setup 1 register per eightbyte. - // So two f32 can be passed in one f64, but 3 f32 have to be passed in 2 FP registers. - // Similarly, two i32 can be passed in one i64, but 3 i32 have to be passed in 2 registers. - // LLVM does not allow us to control registers in this way, nor to request specific - // ABI conventions. So we have to trick it into allocating the right registers, based - // on how clang does it. - - // First, we get the LLVM type corresponding to the C abi for the struct, then - // we pass each field as an argument. - - // Example: - // extern struct { - // x: f32, - // y: f32, - // z: i32, - // }; - // LLVM abi type: { double, i32 } - // const ptr = (*abi_type)*Struct; - // FP Register 1: abi_type[0] - // Register 1: abi_type[1] - - // However, if the struct fits in one register, then we'll pass it as such - size_t number_of_regs = (size_t)ceilf((float)ty_size / (float)8); - - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, ty); - - assert(ty_size <= 16); - - switch (fn_walk->id) { - case FnWalkIdAttrs: { - fn_walk->data.attrs.gen_i += number_of_regs; - break; - } - case FnWalkIdCall: { - LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(abi_type, 0), ""); - if (number_of_regs == 1) { - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, abi_type, abi_ptr_to_struct, ""); - fn_walk->data.call.gen_param_values->append(loaded); - break; - } - for (uint32_t i = 0; i < number_of_regs; i += 1) { - LLVMValueRef adjusted_ptr_to_struct = LLVMBuildStructGEP2(g->builder, - abi_type, abi_ptr_to_struct, i, ""); - LLVMTypeRef field_llvm_ty = LLVMStructGetTypeAtIndex(abi_type, i); - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, field_llvm_ty, - adjusted_ptr_to_struct, ""); - fn_walk->data.call.gen_param_values->append(loaded); - } - break; - } - case FnWalkIdTypes: { - if (number_of_regs == 1) { - fn_walk->data.types.gen_param_types->append(abi_type); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64)); - break; - } - for (uint32_t i = 0; i < number_of_regs; i += 1) { - fn_walk->data.types.gen_param_types->append(LLVMStructGetTypeAtIndex(abi_type, i)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64)); - } - break; - } - case FnWalkIdVars: { - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - di_arg_index = fn_walk->data.vars.gen_i; - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: { - // since we're representing the struct differently as an arg, and potentially - // splitting it, we have to do some work to put it back together. - // the one reg case is straightforward, but if we used two registers we have - // to iterate through the struct abi repr fields and load them one by one. - if (number_of_regs == 1) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); - LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(abi_type, 0); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); - gen_store_untyped(g, arg, bitcasted, var->align_bytes, false); - } else { - LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, var->value_ref, LLVMPointerType(abi_type, 0), ""); - for (uint32_t i = 0; i < number_of_regs; i += 1) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i + i); - LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, false); - LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, false); - LLVMValueRef indices[] = { zero, index }; - LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP2(g->builder, - abi_type, abi_ptr_to_struct, indices, 2, ""); - LLVMBuildStore(g->builder, arg, adjusted_ptr_to_struct); - } - fn_walk->data.inits.gen_i += 1; - } - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - } - return true; - } - } - if (source_node != nullptr) { - give_up_with_c_abi_error(g, source_node); - } - // otherwise allow codegen code to report a compile error - return false; - -var_ok: - if (dest_ty != nullptr && var->decl_node) { - // arg index + 1 because the 0 index is return value - var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, fn_walk->data.vars.import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, dest_ty), !g->strip_debug_symbols, 0, di_arg_index + 1); - } - return true; -} - -void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { - CallingConvention cc = fn_type->data.fn.fn_type_id.cc; - if (!calling_convention_allows_zig_types(cc)) { - size_t src_i = 0; - for (;;) { - if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i)) - break; - src_i += 1; - } - return; - } - if (fn_walk->id == FnWalkIdCall) { - Stage1AirInstCall *instruction = fn_walk->data.call.inst; - bool is_var_args = fn_walk->data.call.is_var_args; - for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { - Stage1AirInst *param_instruction = instruction->args[call_i]; - ZigType *param_type = param_instruction->value->type; - if (is_var_args || type_has_bits(g, param_type)) { - LLVMValueRef param_value = ir_llvm_value(g, param_instruction); - assert(param_value); - fn_walk->data.call.gen_param_values->append(param_value); - fn_walk->data.call.gen_param_types->append(param_type); - } - } - return; - } - size_t next_var_i = 0; - for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { - FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; - size_t gen_index = gen_info->gen_index; - - if (gen_index == SIZE_MAX) { - continue; - } - - switch (fn_walk->id) { - case FnWalkIdAttrs: { - LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn; - bool is_byval = gen_info->is_byval; - FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i]; - - ZigType *param_type = gen_info->type; - if (param_info->is_noalias) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias"); - } - if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); - } - if (get_codegen_ptr_type_bail(g, param_type) != nullptr) { - addLLVMArgAttrInt(llvm_fn, (unsigned)gen_index, "align", get_ptr_align(g, param_type)); - } - if (type_is_nonnull_ptr(g, param_type)) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); - } - break; - } - case FnWalkIdInits: { - ZigFn *fn_table_entry = fn_walk->data.inits.fn; - LLVMValueRef llvm_fn = fn_table_entry->llvm_value; - ZigVar *variable = fn_table_entry->variable_list.at(next_var_i); - assert(variable->src_arg_index != SIZE_MAX); - next_var_i += 1; - - assert(variable); - assert(variable->value_ref); - - if (!handle_is_ptr(g, variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) { - clear_debug_source_node(g); - ZigType *fn_type = fn_table_entry->type_entry; - unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index; - gen_store_untyped(g, LLVMGetParam(llvm_fn, gen_arg_index), - variable->value_ref, variable->align_bytes, false); - } - - if (variable->decl_node) { - gen_var_debug_decl(g, variable); - } - break; - } - case FnWalkIdCall: - // handled before for loop - zig_unreachable(); - case FnWalkIdTypes: - // Not called for non-c-abi - zig_unreachable(); - case FnWalkIdVars: - // iter_function_params_c_abi is called directly for this one - zig_unreachable(); - } - } -} - -static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { - if (g->merge_err_ret_traces_fn_val) - return g->merge_err_ret_traces_fn_val; - - assert(g->stack_trace_type != nullptr); - - LLVMTypeRef param_types[] = { - get_llvm_type(g, ptr_to_stack_trace_type(g)), - get_llvm_type(g, ptr_to_stack_trace_type(g)), - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); - - const char *fn_name = get_mangled_name(g, "__zig_merge_error_return_traces"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); - addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); - - addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); - addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - // this is above the ZigLLVMClearCurrentDebugLocation - LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - // if (dest_stack_trace == null or src_stack_trace == null) return; - // var frame_index: usize = undefined; - // var frames_left: usize = undefined; - // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { - // frame_index = 0; - // frames_left = src_stack_trace.index; - // if (frames_left == 0) return; - // } else { - // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len; - // frames_left = src_stack_trace.instruction_addresses.len; - // } - // while (true) { - // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]); - // frames_left -= 1; - // if (frames_left == 0) return; - // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; - // } - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); - LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull"); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, usize_type_ref, "frame_index"); - LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, usize_type_ref, "frames_left"); - - LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0); - LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1); - - LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr, - LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), ""); - LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr, - LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), ""); - LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, ""); - LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block); - - LLVMPositionBuilderAtEnd(g->builder, non_null_block); - size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), src_stack_trace_ptr, - (unsigned)src_index_field_index, ""); - LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), src_stack_trace_ptr, - (unsigned)src_addresses_field_index, ""); - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(src_addresses_field_ptr), - src_addresses_field_ptr, (unsigned)ptr_field_index, ""); - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(src_addresses_field_ptr), - src_addresses_field_ptr, (unsigned)len_field_index, ""); - LLVMValueRef src_index_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_index_field_ptr), src_index_field_ptr, ""); - LLVMValueRef src_ptr_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_ptr_field_ptr), src_ptr_field_ptr, ""); - LLVMValueRef src_len_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_len_field_ptr), src_len_field_ptr, ""); - LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, ""); - LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap"); - LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap"); - LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop"); - LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block); - - LLVMPositionBuilderAtEnd(g->builder, no_wrap_block); - LLVMValueRef usize_zero = LLVMConstNull(usize_type_ref); - LLVMBuildStore(g->builder, usize_zero, frame_index_ptr); - LLVMBuildStore(g->builder, src_index_val, frames_left_ptr); - LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, ""); - LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block); - LLVMValueRef usize_one = LLVMConstInt(usize_type_ref, 1, false); - LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, ""); - LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, ""); - LLVMBuildStore(g->builder, mod_len, frame_index_ptr); - LLVMBuildStore(g->builder, src_len_val, frames_left_ptr); - LLVMBuildBr(g->builder, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, loop_block); - LLVMValueRef ptr_index = LLVMBuildLoad2(g->builder, usize_type_ref, frame_index_ptr, ""); - LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP2(g->builder, - usize_type_ref, src_ptr_val, &ptr_index, 1, ""); - LLVMValueRef this_addr_val = LLVMBuildLoad2(g->builder, ZigLLVMGetGEPResultElementType(addr_ptr), - addr_ptr, ""); - LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(add_error_return_trace_addr_fn_val), - add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); - LLVMValueRef prev_frames_left = LLVMBuildLoad2(g->builder, usize_type_ref, frames_left_ptr, ""); - LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); - LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); - LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue"); - LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, continue_block); - LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr); - LLVMValueRef prev_index = LLVMBuildLoad2(g->builder, usize_type_ref, frame_index_ptr, ""); - LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, ""); - LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, ""); - LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr); - LLVMBuildBr(g->builder, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->merge_err_ret_traces_fn_val = fn_val; - return fn_val; - -} -static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, Stage1Air *executable, - Stage1AirInstSaveErrRetAddr *save_err_ret_addr_instruction) -{ - assert(g->have_err_ret_tracing); - if ((target_is_wasm(g->zig_target) && g->zig_target->os != OsEmscripten) || target_is_bpf(g->zig_target)) { - return nullptr; - } - - LLVMValueRef return_err_fn = get_return_err_fn(g); - bool is_llvm_alloca; - LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope, - &is_llvm_alloca); - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(return_err_fn), return_err_fn, &my_err_trace_val, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - - ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { - ZigType *frame_type = get_fn_frame_type(g, g->cur_fn); - LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, frame_type), - g->cur_frame_ptr, frame_index_trace_arg(g, ret_type), ""); - LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr); - } - - return nullptr; -} - -static void gen_assert_resume_id(CodeGen *g, Stage1AirInst *source_instr, ResumeId resume_id, PanicMsgId msg_id, - LLVMBasicBlockRef end_bb) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - if (ir_want_runtime_safety(g, source_instr)) { - // Write a value to the resume index which indicates the function was resumed while not suspended. - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - } - - LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); - if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); - LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), - LLVMConstInt(usize_type_ref, resume_id, false)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, ""); - LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); - gen_assertion(g, msg_id, source_instr); - - LLVMPositionBuilderAtEnd(g->builder, end_bb); -} - -static LLVMValueRef gen_resume(CodeGen *g, LLVMTypeRef fn_llvm_ty, LLVMValueRef fn_val, - LLVMValueRef target_frame_ptr, ResumeId resume_id) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - if (fn_val == nullptr) { - LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP2(g->builder, g->any_frame_header_llvm_ty, - target_frame_ptr, frame_fn_ptr_index, ""); - fn_val = LLVMBuildLoad2(g->builder, ZigLLVMGetGEPResultElementType(fn_ptr_ptr), - fn_ptr_ptr, ""); - } - LLVMValueRef arg_val = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), - LLVMConstInt(usize_type_ref, resume_id, false)); - LLVMValueRef args[] = {target_frame_ptr, arg_val}; - return ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, args, 2, ZigLLVM_Fast, - ZigLLVM_CallAttrAuto, ""); -} - -static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint); - size_t new_block_index = g->cur_resume_block_count; - g->cur_resume_block_count += 1; - LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); - LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb); - LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); - return resume_bb; -} - -// Be careful setting tail call. According to LLVM lang ref, -// tail and musttail imply that the callee does not access allocas from the caller. -// This works for async functions since the locals are spilled. -// http://llvm.org/docs/LangRef.html#id320 -static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) { - LLVMSetTailCall(call_inst, true); -} - -static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMValueRef ptr, - LLVMValueRef val, LLVMAtomicOrdering order) -{ - if (g->is_single_threaded) { - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, LLVMTypeOf(val), ptr, ""); - LLVMValueRef modified; - switch (op) { - case LLVMAtomicRMWBinOpXchg: - modified = val; - break; - case LLVMAtomicRMWBinOpXor: - modified = LLVMBuildXor(g->builder, loaded, val, ""); - break; - default: - zig_unreachable(); - } - LLVMBuildStore(g->builder, modified, ptr); - return loaded; - } else { - return LLVMBuildAtomicRMW(g->builder, op, ptr, val, order, false); - } -} - -static void gen_async_return(CodeGen *g, Stage1AirInstReturn *instruction) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value->type : nullptr; - bool operand_has_bits = (operand_type != nullptr) && type_has_bits(g, operand_type); - ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - bool ret_type_has_bits = type_has_bits(g, ret_type); - - if (operand_has_bits && instruction->operand != nullptr) { - bool need_store = instruction->operand->value->special != ConstValSpecialRuntime || !handle_is_ptr(g, ret_type); - if (need_store) { - // It didn't get written to the result ptr. We do that now. - ZigType *ret_ptr_type = get_pointer_to_type(g, ret_type, true); - gen_assign_raw(g, g->cur_ret_ptr, ret_ptr_type, ir_llvm_value(g, instruction->operand)); - } - } - - // Whether we tail resume the awaiter, or do an early return, we are done and will not be resumed. - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref); - LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); - } - - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXor, g->cur_async_awaiter_ptr, - all_ones, LLVMAtomicOrderingAcquire); - - LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn"); - LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); - LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem"); - - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2); - - LLVMAddCase(switch_instr, zero, early_return_block); - LLVMAddCase(switch_instr, all_ones, bad_return_block); - - // Something has gone horribly wrong, and this is an invalid second return. - LLVMPositionBuilderAtEnd(g->builder, bad_return_block); - gen_assertion(g, PanicMsgIdBadReturn, &instruction->base); - - // There is no awaiter yet, but we're completely done. - LLVMPositionBuilderAtEnd(g->builder, early_return_block); - LLVMBuildRetVoid(g->builder); - - // We need to resume the caller by tail calling them, - // but first write through the result pointer and possibly - // error return trace pointer. - LLVMPositionBuilderAtEnd(g->builder, resume_them_block); - - if (ret_type_has_bits) { - // If the awaiter result pointer is non-null, we need to copy the result to there. - LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult"); - LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd"); - LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_ret_start + 1, ""); - LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(awaiter_ret_ptr_ptr), awaiter_ret_ptr_ptr, ""); - LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr)); - LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, ""); - LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block); - - LLVMPositionBuilderAtEnd(g->builder, copy_block); - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, ""); - bool is_volatile = false; - uint32_t abi_align = get_abi_alignment(g, ret_type); - LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false); - ZigLLVMBuildMemCpy(g->builder, - dest_ptr_casted, abi_align, - src_ptr_casted, abi_align, byte_count_val, is_volatile); - LLVMBuildBr(g->builder, copy_end_block); - - LLVMPositionBuilderAtEnd(g->builder, copy_end_block); - if (codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { - LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_index_trace_arg(g, ret_type) + 1, ""); - LLVMValueRef dest_trace_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(awaiter_trace_ptr_ptr), - awaiter_trace_ptr_ptr, ""); - bool is_llvm_alloca; - LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(get_merge_err_ret_traces_fn_val(g)), - get_merge_err_ret_traces_fn_val(g), args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - } - - // Resume the caller by tail calling them. - ZigType *any_frame_type = get_any_frame_type(g, ret_type); - LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val, - get_llvm_type(g, any_frame_type), ""); - LLVMValueRef call_inst = gen_resume(g, g->anyframe_fn_type, nullptr, their_frame_ptr, ResumeIdReturn); - set_tail_call_if_appropriate(g, call_inst); - LLVMBuildRetVoid(g->builder); -} - -static LLVMValueRef gen_convert_to_c_abi(CodeGen *g, LLVMValueRef location, LLVMValueRef value) { - ZigType *return_type = g->cur_fn->type_entry->data.fn.gen_return_type; - size_t size = type_size(g, return_type); - LLVMTypeRef abi_return_type = get_llvm_c_abi_type(g, return_type); - LLVMTypeRef abi_return_type_pointer = LLVMPointerType(abi_return_type, 0); - - if (size < 8) { - LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, value, abi_return_type_pointer, ""); - return LLVMBuildLoad2(g->builder, abi_return_type, bitcast, ""); - } else { - LLVMTypeRef i8ptr = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef bc_location = LLVMBuildBitCast(g->builder, location, i8ptr, ""); - LLVMValueRef bc_value = LLVMBuildBitCast(g->builder, value, i8ptr, ""); - - LLVMValueRef len = LLVMConstInt(LLVMInt64Type(), size, false); - ZigLLVMBuildMemCpy(g->builder, bc_location, 8, bc_value, return_type->abi_align, len, false); - return LLVMBuildLoad2(g->builder, abi_return_type, location, ""); - } -} - -static LLVMValueRef ir_render_return(CodeGen *g, Stage1Air *executable, Stage1AirInstReturn *instruction) { - if (fn_is_async(g->cur_fn)) { - gen_async_return(g, instruction); - return nullptr; - } - - FnTypeId *fn_type_id = &g->cur_fn->type_entry->data.fn.fn_type_id; - - if (want_first_arg_sret(g, fn_type_id)) { - if (instruction->operand == nullptr) { - LLVMBuildRetVoid(g->builder); - return nullptr; - } - assert(g->cur_ret_ptr); - ir_assert(instruction->operand->value->special != ConstValSpecialRuntime, &instruction->base); - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - ZigType *return_type = instruction->operand->value->type; - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); - LLVMBuildRetVoid(g->builder); - } else if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMValueRef location = g->cur_fn->abi_return_value; - if (instruction->operand == nullptr) { - LLVMValueRef converted = gen_convert_to_c_abi(g, location, g->cur_ret_ptr); - LLVMBuildRet(g->builder, converted); - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMValueRef converted = gen_convert_to_c_abi(g, location, value); - LLVMBuildRet(g->builder, converted); - } - } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync && - handle_is_ptr(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) - { - LLVMTypeRef ret_llvm_ty = get_llvm_type(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type); - if (instruction->operand == nullptr) { - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, g->cur_ret_ptr, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, value, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } - } else if (instruction->operand == nullptr) { - if (g->cur_ret_ptr == nullptr) { - LLVMBuildRetVoid(g->builder); - } else { - LLVMTypeRef ret_llvm_ty = get_llvm_type(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type); - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, g->cur_ret_ptr, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMBuildRet(g->builder, value); - } - return nullptr; -} - -static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, - LLVMValueRef val1, LLVMValueRef val2) -{ - // for unsigned left shifting, we do the lossy shift, then logically shift - // right the same number of bits - // if the values don't match, we have an overflow - // for signed left shifting we do the same except arithmetic shift right - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - assert(scalar_type->id == ZigTypeIdInt); - - LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); - LLVMValueRef orig_val; - if (scalar_type->data.integral.is_signed) { - orig_val = LLVMBuildAShr(g->builder, result, val2, ""); - } else { - orig_val = LLVMBuildLShr(g->builder, result, val2, ""); - } - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShlOverflowedBits); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type, - LLVMValueRef val1, LLVMValueRef val2) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - assert(scalar_type->id == ZigTypeIdInt); - - LLVMValueRef result; - if (scalar_type->data.integral.is_signed) { - result = LLVMBuildAShr(g->builder, val1, val2, ""); - } else { - result = LLVMBuildLShr(g->builder, val1, val2, ""); - } - LLVMValueRef orig_val = LLVMBuildShl(g->builder, result, val2, ""); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShrOverflowedBits); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type) { - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, name); - if (existing_llvm_fn != nullptr) return existing_llvm_fn; - LLVMValueRef existing_llvm_alias = LLVMGetNamedGlobalAlias(g->module, name, strlen(name)); - if (existing_llvm_alias != nullptr) return LLVMAliasGetAliasee(existing_llvm_alias); - - LLVMTypeRef param_types[3] = { param_type, param_type, param_type }; - LLVMTypeRef fn_type = LLVMFunctionType(return_type, param_types, param_count, false); - return LLVMAddFunction(g->module, name, fn_type); -} - -static LLVMValueRef gen_soft_float_un_op(CodeGen *g, LLVMValueRef op, ZigType *operand_type, BuiltinFnId op_id) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - ZigType *scalar_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - - char fn_name[64]; - snprintf(fn_name, sizeof(fn_name), "%s%s%s", libc_float_prefix(g, scalar_type), - float_un_op_to_name(op_id), libc_float_suffix(g, scalar_type)); - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, scalar_type->llvm_type, scalar_type->llvm_type); - - if (vector_len == 0) { - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &op, 1, ""); - } else { - LLVMValueRef result = LLVMGetUndef(operand_type->llvm_type); - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - LLVMValueRef param = LLVMBuildExtractElement(g->builder, op, index_value, ""); - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, ¶m, 1, ""); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - return result; - } -} - -static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *operand_type, BuiltinFnId op) { - assert(operand_type->id == ZigTypeIdFloat || operand_type->id == ZigTypeIdVector); - ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (elem_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target)) || - op == BuiltinFnIdTan) - { - return gen_soft_float_un_op(g, operand, operand_type, op); - } - LLVMValueRef float_op_fn = get_float_fn(g, operand_type, ZigLLVMFnIdFloatOp, op); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(float_op_fn), float_op_fn, &operand, 1, ""); -} - -enum DivKind { - DivKindFloat, - DivKindTrunc, - DivKindFloor, - DivKindExact, -}; - -static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { - if (bigint->digit_count == 0) { - return LLVMConstNull(type_ref); - } - - if (LLVMGetTypeKind(type_ref) == LLVMVectorTypeKind) { - const unsigned vector_len = LLVMGetVectorSize(type_ref); - LLVMTypeRef elem_type = LLVMGetElementType(type_ref); - - LLVMValueRef *values = heap::c_allocator.allocate_nonzero(vector_len); - // Create a vector with all the elements having the same value - for (unsigned i = 0; i < vector_len; i++) { - values[i] = bigint_to_llvm_const(elem_type, bigint); - } - LLVMValueRef result = LLVMConstVector(values, vector_len); - heap::c_allocator.deallocate(values, vector_len); - return result; - } - - LLVMValueRef unsigned_val; - if (bigint->digit_count == 1) { - unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false); - } else { - unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint)); - } - if (bigint->is_negative) { - return LLVMConstNeg(unsigned_val); - } else { - return unsigned_val; - } -} - -static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, - LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, DivKind div_kind) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - ZigLLVMSetFastMath(g->builder, want_fast_math); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); - if (want_runtime_safety && (want_fast_math || scalar_type->id != ZigTypeIdFloat)) { - // Safety check: divisor != 0 - LLVMValueRef is_zero_bit; - if (scalar_type->id == ZigTypeIdInt) { - is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); - } else { - zig_unreachable(); - } - - if (operand_type->id == ZigTypeIdVector) { - is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit); - } - - LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); - LLVMBasicBlockRef div_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk"); - LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, div_zero_fail_block); - gen_safety_crash(g, PanicMsgIdDivisionByZero); - - LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block); - - // Safety check: check for overflow (dividend = minInt and divisor = -1) - if (scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) { - LLVMValueRef neg_1_value = LLVMConstAllOnes(get_llvm_type(g, operand_type)); - BigInt int_min_bi = {0}; - eval_min_max_value_int(g, scalar_type, &int_min_bi, false); - LLVMValueRef int_min_value = bigint_to_llvm_const(get_llvm_type(g, operand_type), &int_min_bi); - - LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail"); - LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk"); - LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, ""); - LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); - LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); - if (operand_type->id == ZigTypeIdVector) { - overflow_fail_bit = ZigLLVMBuildOrReduce(g->builder, overflow_fail_bit); - } - LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block); - gen_safety_crash(g, PanicMsgIdIntegerOverflow); - - LLVMPositionBuilderAtEnd(g->builder, overflow_ok_block); - } - } - - if (scalar_type->id == ZigTypeIdFloat) { - LLVMValueRef result = LLVMBuildFDiv(g->builder, val1, val2, ""); - switch (div_kind) { - case DivKindFloat: - return result; - case DivKindExact: - if (want_runtime_safety) { - // Safety check: a / b == floor(a / b) - LLVMValueRef floored = gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - case DivKindTrunc: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdTrunc); - case DivKindFloor: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - } - zig_unreachable(); - } - - assert(scalar_type->id == ZigTypeIdInt); - - switch (div_kind) { - case DivKindFloat: - zig_unreachable(); - case DivKindTrunc: - if (scalar_type->data.integral.is_signed) { - return LLVMBuildSDiv(g->builder, val1, val2, ""); - } else { - return LLVMBuildUDiv(g->builder, val1, val2, ""); - } - case DivKindExact: - if (want_runtime_safety) { - // Safety check: a % b == 0 - LLVMValueRef remainder_val; - if (scalar_type->data.integral.is_signed) { - remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); - } else { - remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - if (scalar_type->data.integral.is_signed) { - return LLVMBuildExactSDiv(g->builder, val1, val2, ""); - } else { - return LLVMBuildExactUDiv(g->builder, val1, val2, ""); - } - case DivKindFloor: - { - if (!scalar_type->data.integral.is_signed) { - return LLVMBuildUDiv(g->builder, val1, val2, ""); - } - // const d = @divTrunc(a, b); - // const r = @rem(a, b); - // return if (r == 0) d else d - ((a < 0) ^ (b < 0)); - - LLVMValueRef div_trunc = LLVMBuildSDiv(g->builder, val1, val2, ""); - LLVMValueRef rem = LLVMBuildSRem(g->builder, val1, val2, ""); - LLVMValueRef rem_eq_0 = LLVMBuildICmp(g->builder, LLVMIntEQ, rem, zero, ""); - LLVMValueRef a_lt_0 = LLVMBuildICmp(g->builder, LLVMIntSLT, val1, zero, ""); - LLVMValueRef b_lt_0 = LLVMBuildICmp(g->builder, LLVMIntSLT, val2, zero, ""); - LLVMValueRef a_b_xor = LLVMBuildXor(g->builder, a_lt_0, b_lt_0, ""); - LLVMValueRef a_b_xor_ext = LLVMBuildZExt(g->builder, a_b_xor, LLVMTypeOf(div_trunc), ""); - LLVMValueRef d_sub_xor = LLVMBuildSub(g->builder, div_trunc, a_b_xor_ext, ""); - return LLVMBuildSelect(g->builder, rem_eq_0, div_trunc, d_sub_xor, ""); - } - } - zig_unreachable(); -} - -enum RemKind { - RemKindRem, - RemKindMod, -}; - -static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast_math, - LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, RemKind rem_kind) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - ZigLLVMSetFastMath(g->builder, want_fast_math); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); - if (want_runtime_safety) { - // Safety check: divisor != 0 - LLVMValueRef is_zero_bit; - if (scalar_type->id == ZigTypeIdInt) { - LLVMIntPredicate pred = scalar_type->data.integral.is_signed ? LLVMIntSLE : LLVMIntEQ; - is_zero_bit = LLVMBuildICmp(g->builder, pred, val2, zero, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); - } else { - zig_unreachable(); - } - - if (operand_type->id == ZigTypeIdVector) { - is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit); - } - - LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); - LLVMBasicBlockRef rem_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroFail"); - LLVMBuildCondBr(g->builder, is_zero_bit, rem_zero_fail_block, rem_zero_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, rem_zero_fail_block); - gen_safety_crash(g, PanicMsgIdRemainderDivisionByZero); - - LLVMPositionBuilderAtEnd(g->builder, rem_zero_ok_block); - } - - if (scalar_type->id == ZigTypeIdFloat) { - if (rem_kind == RemKindRem) { - return LLVMBuildFRem(g->builder, val1, val2, ""); - } else { - LLVMValueRef a = LLVMBuildFRem(g->builder, val1, val2, ""); - LLVMValueRef b = LLVMBuildFAdd(g->builder, a, val2, ""); - LLVMValueRef c = LLVMBuildFRem(g->builder, b, val2, ""); - LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); - return LLVMBuildSelect(g->builder, ltz, c, a, ""); - } - } else { - assert(scalar_type->id == ZigTypeIdInt); - if (scalar_type->data.integral.is_signed) { - if (rem_kind == RemKindRem) { - return LLVMBuildSRem(g->builder, val1, val2, ""); - } else { - LLVMValueRef a = LLVMBuildSRem(g->builder, val1, val2, ""); - LLVMValueRef b = LLVMBuildNSWAdd(g->builder, a, val2, ""); - LLVMValueRef c = LLVMBuildSRem(g->builder, b, val2, ""); - LLVMValueRef ltz = LLVMBuildICmp(g->builder, LLVMIntSLT, val1, zero, ""); - return LLVMBuildSelect(g->builder, ltz, c, a, ""); - } - } else { - return LLVMBuildURem(g->builder, val1, val2, ""); - } - } - -} - -static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type, LLVMValueRef value) { - // We only check if the rhs value of the shift expression is greater or - // equal to the number of bits of the lhs if it's not a power of two, - // otherwise the check is useful as the allowed values are limited by the - // operand type itself - if (!is_power_of_2(lhs_type->data.integral.bit_count)) { - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, lhs_type->data.integral.bit_count); - LLVMValueRef bit_count_value = bigint_to_llvm_const(get_llvm_type(g, rhs_type), - &bit_count_bi); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk"); - LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, ""); - if (rhs_type->id == ZigTypeIdVector) { - less_than_bit = ZigLLVMBuildOrReduce(g->builder, less_than_bit); - } - LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShxTooBigRhs); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } -} - -enum Icmp { - NONE, - EQ_ZERO, - NE_ZERO, - LE_ZERO, - EQ_NEG, - GE_ZERO, - EQ_ONE, -}; - -static LLVMValueRef add_icmp(CodeGen *g, LLVMValueRef val, Icmp kind) { - switch (kind) { - case NONE: - return val; - case EQ_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - case NE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntNE, val, zero, ""); - } - case LE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntSLE, val, zero, ""); - } - case EQ_NEG: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, -1, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - case GE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntSGE, val, zero, ""); - } - case EQ_ONE: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 1, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - default: - zig_unreachable(); - } -} - -static LLVMValueRef gen_soft_int_to_float_op(CodeGen *g, LLVMValueRef value_ref, ZigType *operand_type, ZigType *result_type) { - // Handle integers of non-pot bitsize by widening them. - const size_t bitsize = operand_type->data.integral.bit_count; - const bool is_signed = operand_type->data.integral.is_signed; - if (bitsize < 32 || !is_power_of_2(bitsize)) { - const size_t wider_bitsize = bitsize < 32 ? 32 : round_to_next_power_of_2(bitsize); - ZigType *wider_type = get_int_type(g, is_signed, wider_bitsize); - value_ref = gen_widen_or_shorten(g, false, operand_type, wider_type, value_ref); - operand_type = wider_type; - } - assert(bitsize <= 128); - - const char *int_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_type); - const char *float_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(result_type); - - char fn_name[64]; - if (is_signed) { - snprintf(fn_name, sizeof(fn_name), "__float%si%sf", int_compiler_rt_type_abbrev, float_compiler_rt_type_abbrev); - } else { - snprintf(fn_name, sizeof(fn_name), "__floatun%si%sf", int_compiler_rt_type_abbrev, float_compiler_rt_type_abbrev); - } - - int param_count = 1; - LLVMValueRef func_ref; - if ((operand_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard i128 calling - // convention to adhere to the ABI that LLVM expects compiler-rt to have. - LLVMTypeRef v2i64 = LLVMVectorType(LLVMInt64Type(), 2); - value_ref = LLVMBuildBitCast(g->builder, value_ref, v2i64, ""); - func_ref = get_soft_float_fn(g, fn_name, param_count, v2i64, result_type->llvm_type); - } else { - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, result_type->llvm_type); - } - - LLVMValueRef params[1] = {value_ref}; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); -} - -static LLVMValueRef gen_soft_float_to_int_op(CodeGen *g, LLVMValueRef value_ref, ZigType *operand_type, ZigType *result_type) { - // Handle integers of non-pot bitsize by truncating a sufficiently wide pot integer - const size_t bitsize = result_type->data.integral.bit_count; - const bool is_signed = result_type->data.integral.is_signed; - ZigType * wider_type = result_type; - if (bitsize < 32 || !is_power_of_2(bitsize)) { - const size_t wider_bitsize = bitsize < 32 ? 32 : round_to_next_power_of_2(bitsize); - wider_type = get_int_type(g, is_signed, wider_bitsize); - } - assert(bitsize <= 128); - - const char *float_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_type); - const char *int_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(wider_type); - - char fn_name[64]; - if (is_signed) { - snprintf(fn_name, sizeof(fn_name), "__fix%sf%si", float_compiler_rt_type_abbrev, int_compiler_rt_type_abbrev); - } else { - snprintf(fn_name, sizeof(fn_name), "__fixuns%sf%si", float_compiler_rt_type_abbrev, int_compiler_rt_type_abbrev); - } - - int param_count = 1; - LLVMValueRef func_ref; - if ((wider_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard i128 calling - // convention to adhere to the ABI that LLVM expects compiler-rt to have. - LLVMTypeRef v2i64 = LLVMVectorType(LLVMInt64Type(), 2); - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, v2i64); - } else { - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, wider_type->llvm_type); - } - - LLVMValueRef params[1] = {value_ref}; - LLVMValueRef result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - - if ((wider_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - result = LLVMBuildBitCast(g->builder, result, wider_type->llvm_type, ""); - } - - // Handle integers of non-pot bitsize by shortening them on the output - if (result_type != wider_type) { - result = gen_widen_or_shorten(g, false, wider_type, result_type, result); - } - - return result; -} - -static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LLVMValueRef op2_value, ZigType *operand_type, IrBinOp op_id) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - - int param_count = 2; - - ZigType *operand_scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - LLVMTypeRef return_scalar_type = operand_scalar_type->llvm_type; - const char *compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_scalar_type); - const char *math_float_prefix = libc_float_prefix(g, operand_scalar_type); - const char *math_float_suffix = libc_float_suffix(g, operand_scalar_type); - - char fn_name[64]; - Icmp res_icmp = NONE; - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpMultWrap: - case IrBinOpAddWrap: - case IrBinOpSubWrap: - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - case IrBinOpShlSat: - zig_unreachable(); - case IrBinOpCmpEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__eq%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_ZERO; - break; - case IrBinOpCmpNotEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ne%sf2", compiler_rt_type_abbrev); - res_icmp = NE_ZERO; - break; - case IrBinOpCmpLessOrEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__le%sf2", compiler_rt_type_abbrev); - res_icmp = LE_ZERO; - break; - case IrBinOpCmpLessThan: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__le%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_NEG; - break; - case IrBinOpCmpGreaterOrEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ge%sf2", compiler_rt_type_abbrev); - res_icmp = GE_ZERO; - break; - case IrBinOpCmpGreaterThan: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ge%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_ONE; - break; - case IrBinOpMax: - snprintf(fn_name, sizeof(fn_name), "%sfmax%s", math_float_prefix, math_float_suffix); - break; - case IrBinOpMin: - snprintf(fn_name, sizeof(fn_name), "%sfmin%s", math_float_prefix, math_float_suffix); - break; - case IrBinOpMult: - snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpAdd: - snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpSub: - snprintf(fn_name, sizeof(fn_name), "__sub%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpDivUnspecified: - case IrBinOpDivExact: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - snprintf(fn_name, sizeof(fn_name), "__div%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpRemRem: - case IrBinOpRemMod: - snprintf(fn_name, sizeof(fn_name), "%sfmod%s", math_float_prefix, math_float_suffix); - break; - default: - zig_unreachable(); - } - - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, param_count, operand_scalar_type->llvm_type, return_scalar_type); - - LLVMValueRef result; - if (vector_len == 0) { - LLVMValueRef params[2] = {op1_value, op2_value}; - result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - result = add_icmp(g, result, res_icmp); - } else { - ZigType *alloca_ty = operand_type; - if (res_icmp != NONE) alloca_ty = get_vector_type(g, vector_len, g->builtin_types.entry_bool); - result = LLVMGetUndef(alloca_ty->llvm_type); - - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - LLVMValueRef params[2] = { - LLVMBuildExtractElement(g->builder, op1_value, index_value, ""), - LLVMBuildExtractElement(g->builder, op2_value, index_value, ""), - }; - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - call_result = add_icmp(g, call_result, res_icmp); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - } - - // Some operations are implemented as compound ops and require us to perform some - // more operations before we obtain the final result - switch (op_id) { - case IrBinOpDivTrunc: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdTrunc); - case IrBinOpDivFloor: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - case IrBinOpRemMod: - { - LLVMValueRef b = gen_soft_float_bin_op(g, result, op2_value, operand_type, IrBinOpAdd); - LLVMValueRef wrapped_result = gen_soft_float_bin_op(g, b, op2_value, operand_type, IrBinOpRemRem); - LLVMValueRef zero = LLVMConstNull(operand_type->llvm_type); - LLVMValueRef ltz = gen_soft_float_bin_op(g, op1_value, zero, operand_type, IrBinOpCmpLessThan); - - return LLVMBuildSelect(g->builder, ltz, wrapped_result, result, ""); - } - case IrBinOpDivExact: - { - LLVMValueRef floored = gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - LLVMValueRef ok_bit = gen_soft_float_bin_op(g, result, floored, operand_type, IrBinOpCmpEq); - if (vector_len != 0) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - default: - return result; - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, - Stage1AirInstBinOp *bin_op_instruction) -{ - IrBinOp op_id = bin_op_instruction->op_id; - Stage1AirInst *op1 = bin_op_instruction->op1; - Stage1AirInst *op2 = bin_op_instruction->op2; - - ZigType *operand_type = op1->value->type; - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`. - // On some targets this will be incorrect, so we manually lower the call ourselves. - LLVMValueRef op1_value = ir_llvm_value(g, op1); - LLVMValueRef op2_value = ir_llvm_value(g, op2); - return gen_soft_float_bin_op(g, op1_value, op2_value, operand_type, op_id); - } - - - bool want_runtime_safety = bin_op_instruction->safety_check_on && - ir_want_runtime_safety(g, &bin_op_instruction->base); - - LLVMValueRef op1_value = ir_llvm_value(g, op1); - LLVMValueRef op2_value = ir_llvm_value(g, op2); - - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - zig_unreachable(); - case IrBinOpBoolOr: - return LLVMBuildOr(g->builder, op1_value, op2_value, ""); - case IrBinOpBoolAnd: - return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); - return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, scalar_type->data.integral.is_signed); - return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdEnum || - scalar_type->id == ZigTypeIdErrorSet || - scalar_type->id == ZigTypeIdBool || - get_codegen_ptr_type_bail(g, scalar_type) != nullptr) - { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); - return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else { - zig_unreachable(); - } - case IrBinOpMult: - case IrBinOpMultWrap: - case IrBinOpAdd: - case IrBinOpAddWrap: - case IrBinOpSub: - case IrBinOpSubWrap: { - bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); - AddSubMul add_sub_mul = - op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : - op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : - AddSubMulMul; - - if (scalar_type->id == ZigTypeIdPointer) { - LLVMValueRef subscript_value; - if (operand_type->id == ZigTypeIdVector) - zig_panic("TODO: Implement vector operations on pointers."); - - switch (add_sub_mul) { - case AddSubMulAdd: - subscript_value = op2_value; - break; - case AddSubMulSub: - subscript_value = LLVMBuildNeg(g->builder, op2_value, ""); - break; - case AddSubMulMul: - zig_unreachable(); - } - - // TODO runtime safety - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, scalar_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, op1_value, - &subscript_value, 1, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (is_wrapping) { - return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else if (want_runtime_safety) { - return gen_overflow_op(g, operand_type, add_sub_mul, op1_value, op2_value); - } else if (scalar_type->data.integral.is_signed) { - return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else { - return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - } - case IrBinOpBinOr: - return LLVMBuildOr(g->builder, op1_value, op2_value, ""); - case IrBinOpBinXor: - return LLVMBuildXor(g->builder, op1_value, op2_value, ""); - case IrBinOpBinAnd: - return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - { - assert(scalar_type->id == ZigTypeIdInt); - LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value, - LLVMTypeOf(op1_value), ""); - - if (want_runtime_safety) { - gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value); - } - - bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); - if (is_sloppy) { - return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); - } else if (want_runtime_safety) { - return gen_overflow_shl_op(g, operand_type, op1_value, op2_casted); - } else if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); - } else { - return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, ""); - } - } - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - { - assert(scalar_type->id == ZigTypeIdInt); - LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value, - LLVMTypeOf(op1_value), ""); - - if (want_runtime_safety) { - gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value); - } - - bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); - if (is_sloppy) { - if (scalar_type->data.integral.is_signed) { - return LLVMBuildAShr(g->builder, op1_value, op2_casted, ""); - } else { - return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); - } - } else if (want_runtime_safety) { - return gen_overflow_shr_op(g, operand_type, op1_value, op2_casted); - } else if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); - } else { - return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); - } - } - case IrBinOpDivUnspecified: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindFloat); - case IrBinOpDivExact: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindExact); - case IrBinOpDivTrunc: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindTrunc); - case IrBinOpDivFloor: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindFloor); - case IrBinOpRemRem: - return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, RemKindRem); - case IrBinOpRemMod: - return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, RemKindMod); - case IrBinOpMax: - if (scalar_type->id == ZigTypeIdFloat) { - return ZigLLVMBuildMaxNum(g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMax(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMax(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpMin: - if (scalar_type->id == ZigTypeIdFloat) { - return ZigLLVMBuildMinNum(g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMin(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMin(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpAddSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUAddSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpSubSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUSubSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpMultSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMulFixSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpShlSat: { - if (scalar_type->id != ZigTypeIdInt) { - zig_unreachable(); - } - LLVMValueRef result = scalar_type->data.integral.is_signed ? - ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "") : - ZigLLVMBuildUShlSat(g->builder, op1_value, op2_value, ""); - // LLVM langref says "If b is (statically or dynamically) equal to or - // larger than the integer bit width of the arguments, the result is a - // poison value." - // However Zig semantics says that saturating shift left can never produce - // undefined; instead it saturates. - LLVMTypeRef lhs_scalar_llvm_ty = get_llvm_type(g, scalar_type); - LLVMValueRef bits = LLVMConstInt(lhs_scalar_llvm_ty, - scalar_type->data.integral.bit_count, false); - LLVMValueRef lhs_max = LLVMConstAllOnes(lhs_scalar_llvm_ty); - if (operand_type->id == ZigTypeIdVector) { - uint64_t vec_len = operand_type->data.vector.len; - LLVMValueRef bits_vec = LLVMBuildVectorSplat(g->builder, vec_len, bits, ""); - LLVMValueRef lhs_max_vec = LLVMBuildVectorSplat(g->builder, vec_len, lhs_max, ""); - LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits_vec, ""); - return LLVMBuildSelect(g->builder, in_range, result, lhs_max_vec, ""); - } else { - LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits, ""); - return LLVMBuildSelect(g->builder, in_range, result, lhs_max, ""); - } - } - } - zig_unreachable(); -} - -static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *int_type, LLVMValueRef target_val) { - assert(err_set_type->id == ZigTypeIdErrorSet); - - if (type_is_global_error_set(err_set_type)) { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type)); - LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, ""); - LLVMValueRef ok_bit; - - BigInt biggest_possible_err_val = {0}; - eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true); - - if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && - bigint_as_usize(&biggest_possible_err_val) < g->errors_by_index.length) - { - ok_bit = neq_zero_bit; - } else { - LLVMValueRef error_value_count = LLVMConstInt(get_llvm_type(g, int_type), g->errors_by_index.length, false); - LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, ""); - ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, ""); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail"); - - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdInvalidErrorCode); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } else { - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail"); - - uint32_t err_count = err_set_type->data.error_set.err_count; - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_val, fail_block, err_count); - for (uint32_t i = 0; i < err_count; i += 1) { - LLVMValueRef case_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type), - err_set_type->data.error_set.errors[i]->value, false); - LLVMAddCase(switch_instr, case_value, ok_block); - } - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdInvalidErrorCode); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } -} - -static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstCast *cast_instruction) -{ - Error err; - ZigType *actual_type = cast_instruction->value->value->type; - ZigType *wanted_type = cast_instruction->base.value->type; - bool wanted_type_has_bits; - if ((err = type_has_bits2(g, wanted_type, &wanted_type_has_bits))) - codegen_report_errors_and_exit(g); - if (!wanted_type_has_bits) - return nullptr; - LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value); - ir_assert(expr_val, &cast_instruction->base); - - switch (cast_instruction->cast_op) { - case CastOpNoCast: - case CastOpNumLitToConcrete: - zig_unreachable(); - case CastOpNoop: - if (actual_type->id == ZigTypeIdPointer && wanted_type->id == ZigTypeIdPointer && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - wanted_type->data.pointer.child_type->id == ZigTypeIdArray) - { - return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return expr_val; - } - case CastOpIntToFloat: - assert(actual_type->id == ZigTypeIdInt); - { - if ((wanted_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (wanted_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (wanted_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type); - } else { - if (actual_type->data.integral.is_signed) { - return LLVMBuildSIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return LLVMBuildUIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } - } - case CastOpFloatToInt: { - assert(wanted_type->id == ZigTypeIdInt); - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base)); - - bool want_safety = ir_want_runtime_safety(g, &cast_instruction->base); - - LLVMValueRef result; - if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (actual_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type); - } else { - if (wanted_type->data.integral.is_signed) { - result = LLVMBuildFPToSI(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - result = LLVMBuildFPToUI(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } - - if (want_safety) { - LLVMValueRef back_to_float; - if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) { - back_to_float = gen_soft_int_to_float_op(g, result, wanted_type, actual_type); - } else { - if (wanted_type->data.integral.is_signed) { - back_to_float = LLVMBuildSIToFP(g->builder, result, LLVMTypeOf(expr_val), ""); - } else { - back_to_float = LLVMBuildUIToFP(g->builder, result, LLVMTypeOf(expr_val), ""); - } - } - LLVMValueRef difference = LLVMBuildFSub(g->builder, expr_val, back_to_float, ""); - LLVMValueRef one_pos = LLVMConstReal(LLVMTypeOf(expr_val), 1.0f); - LLVMValueRef one_neg = LLVMConstReal(LLVMTypeOf(expr_val), -1.0f); - LLVMValueRef ok_bit_pos = LLVMBuildFCmp(g->builder, LLVMRealOLT, difference, one_pos, ""); - LLVMValueRef ok_bit_neg = LLVMBuildFCmp(g->builder, LLVMRealOGT, difference, one_neg, ""); - LLVMValueRef ok_bit = LLVMBuildAnd(g->builder, ok_bit_pos, ok_bit_neg, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckOk"); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, bad_block); - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdFloatToInt); - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - } - case CastOpBoolToInt: - assert(wanted_type->id == ZigTypeIdInt); - assert(actual_type->id == ZigTypeIdBool); - return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - case CastOpErrSet: - if (ir_want_runtime_safety(g, &cast_instruction->base)) { - add_error_range_check(g, wanted_type, g->err_tag_type, expr_val); - } - return expr_val; - case CastOpBitCast: - return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, Stage1Air *executable, - Stage1AirInstPtrOfArrayToSlice *instruction) -{ - ZigType *actual_type = instruction->operand->value->type; - ZigType *slice_type = instruction->base.value->type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - size_t ptr_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - size_t len_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - assert(actual_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - - if (type_has_bits(g, actual_type)) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), - result_loc, ptr_index, ""); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), - }; - LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, - get_llvm_type(g, array_type), expr_val, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - } else if (ir_want_runtime_safety(g, &instruction->base) && ptr_index != SIZE_MAX) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), result_loc, ptr_index, ""); - gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr); - } - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), result_loc, len_index, ""); - LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - array_type->data.array.len, false); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return result_loc; -} - -static LLVMValueRef ir_render_ptr_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstPtrCast *instruction) -{ - ZigType *wanted_type = instruction->base.value->type; - if (!type_has_bits(g, wanted_type)) { - return nullptr; - } - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, get_llvm_type(g, wanted_type), ""); - bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - if (!want_safety_check || ptr_allows_addr_zero(wanted_type)) - return result_ptr; - - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, ""); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdPtrCastNull); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result_ptr; -} - -static LLVMValueRef ir_render_bit_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstBitCast *instruction) -{ - ZigType *wanted_type = instruction->base.value->type; - ZigType *actual_type = instruction->operand->value->type; - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - - bool wanted_is_ptr = handle_is_ptr(g, wanted_type); - bool actual_is_ptr = handle_is_ptr(g, actual_type); - if (wanted_is_ptr == actual_is_ptr) { - // We either bitcast the value directly or bitcast the pointer which does a pointer cast - LLVMTypeRef wanted_type_ref = wanted_is_ptr ? - LLVMPointerType(get_llvm_type(g, wanted_type), 0) : get_llvm_type(g, wanted_type); - return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); - } else if (actual_is_ptr) { - // A scalar is wanted but we got a pointer - LLVMTypeRef wanted_elem_type_ref = get_llvm_type(g, wanted_type); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, - LLVMPointerType(wanted_elem_type_ref, 0), ""); - uint32_t alignment = get_abi_alignment(g, actual_type); - return gen_load_untyped(g, wanted_elem_type_ref, bitcasted_ptr, alignment, false, ""); - } else { - // A pointer is wanted but we got a scalar - assert(actual_type->id == ZigTypeIdPointer); - LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, wanted_type), 0); - return LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); - } -} - -static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, Stage1Air *executable, - Stage1AirInstWidenOrShorten *instruction) -{ - ZigType *actual_type = instruction->target->value->type; - // TODO instead of this logic, use the Noop instruction to change the type from - // enum_tag to the underlying int type - ZigType *int_type; - if (actual_type->id == ZigTypeIdEnum) { - int_type = actual_type->data.enumeration.tag_int_type; - } else { - int_type = actual_type; - } - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), int_type, - instruction->base.value->type, target_val); -} - -static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToPtr *instruction) { - ZigType *wanted_type = instruction->base.value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - const uint32_t align_bytes = get_ptr_align(g, wanted_type); - - if (ir_want_runtime_safety(g, &instruction->base)) { - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef zero = LLVMConstNull(usize->llvm_type); - - if (!ptr_allows_addr_zero(wanted_type)) { - LLVMValueRef is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, target_val, zero, ""); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntBad"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntOk"); - LLVMBuildCondBr(g->builder, is_zero_bit, bad_block, ok_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdPtrCastNull); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (align_bytes > 1) { - LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->llvm_type, align_bytes - 1, false); - LLVMValueRef anded_val = LLVMBuildAnd(g->builder, target_val, alignment_minus_1, ""); - LLVMValueRef is_ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, zero, ""); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntAlignBad"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntAlignOk"); - LLVMBuildCondBr(g->builder, is_ok_bit, ok_block, bad_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdIncorrectAlignment); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - } - return LLVMBuildIntToPtr(g->builder, target_val, get_llvm_type(g, wanted_type), ""); -} - -static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, Stage1Air *executable, Stage1AirInstPtrToInt *instruction) { - ZigType *wanted_type = instruction->base.value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return LLVMBuildPtrToInt(g->builder, target_val, get_llvm_type(g, wanted_type), ""); -} - -static LLVMValueRef ir_render_int_to_enum(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToEnum *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdEnum); - ZigType *tag_int_type = wanted_type->data.enumeration.tag_int_type; - - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - instruction->target->value->type, tag_int_type, target_val); - - if (ir_want_runtime_safety(g, &instruction->base) && !wanted_type->data.enumeration.non_exhaustive) { - LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); - LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue"); - size_t field_count = wanted_type->data.enumeration.src_field_count; - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - for (size_t field_i = 0; field_i < field_count; field_i += 1) { - TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i]; - - Buf *name = type_enum_field->name; - auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); - if (entry != nullptr) { - continue; - } - - LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type), - &type_enum_field->value); - LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block); - } - occupied_tag_values.deinit(); - LLVMPositionBuilderAtEnd(g->builder, bad_value_block); - gen_safety_crash(g, PanicMsgIdBadEnumValue); - - LLVMPositionBuilderAtEnd(g->builder, ok_value_block); - } - return tag_int_value; -} - -static LLVMValueRef ir_render_int_to_err(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToErr *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdErrorSet); - - ZigType *actual_type = instruction->target->value->type; - assert(actual_type->id == ZigTypeIdInt); - assert(!actual_type->data.integral.is_signed); - - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - - if (ir_want_runtime_safety(g, &instruction->base)) { - add_error_range_check(g, wanted_type, actual_type, target_val); - } - - return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val); -} - -static LLVMValueRef ir_render_err_to_int(CodeGen *g, Stage1Air *executable, Stage1AirInstErrToInt *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdInt); - assert(!wanted_type->data.integral.is_signed); - - ZigType *actual_type = instruction->target->value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - - if (actual_type->id == ZigTypeIdErrorSet) { - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - g->err_tag_type, wanted_type, target_val); - } else if (actual_type->id == ZigTypeIdErrorUnion) { - // this should have been a compile time constant - assert(type_has_bits(g, actual_type->data.error_union.err_set_type)); - - if (!type_has_bits(g, actual_type->data.error_union.payload_type)) { - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - g->err_tag_type, wanted_type, target_val); - } else { - zig_panic("TODO err to int when error union payload type not void"); - } - } else { - zig_unreachable(); - } -} - -static LLVMValueRef ir_render_unreachable(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnreachable *unreachable_instruction) -{ - if (ir_want_runtime_safety(g, &unreachable_instruction->base)) { - gen_safety_crash(g, PanicMsgIdUnreachable); - } else { - LLVMBuildUnreachable(g->builder); - } - return nullptr; -} - -static LLVMValueRef ir_render_cond_br(CodeGen *g, Stage1Air *executable, - Stage1AirInstCondBr *cond_br_instruction) -{ - LLVMBuildCondBr(g->builder, - ir_llvm_value(g, cond_br_instruction->condition), - cond_br_instruction->then_block->llvm_block, - cond_br_instruction->else_block->llvm_block); - return nullptr; -} - -static LLVMValueRef ir_render_br(CodeGen *g, Stage1Air *executable, Stage1AirInstBr *br_instruction) { - LLVMBuildBr(g->builder, br_instruction->dest_block->llvm_block); - return nullptr; -} - -static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable, - Stage1AirInstBinaryNot *inst) -{ - LLVMValueRef operand = ir_llvm_value(g, inst->operand); - return LLVMBuildNot(g->builder, operand, ""); -} - -static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - uint16_t num_bits = operand_type->id == ZigTypeIdVector ? - operand_type->data.vector.elem_type->data.floating.bit_count : - operand_type->data.floating.bit_count; - - ZigType *iX_type = get_int_type(g, true, num_bits); - LLVMValueRef sign_mask = LLVMConstShl( - LLVMConstInt(iX_type->llvm_type, 1, false), - LLVMConstInt(iX_type->llvm_type, num_bits - 1, false)); - - LLVMValueRef sign_mask_splat = (vector_len == 0) ? sign_mask : - LLVMBuildVectorSplat(g->builder, vector_len, sign_mask, ""); - - LLVMValueRef bitcasted_operand = LLVMBuildBitCast(g->builder, operand, - (vector_len == 0) ? - iX_type->llvm_type : - get_vector_type(g, vector_len, iX_type)->llvm_type, - ""); - - LLVMValueRef result = LLVMBuildXor(g->builder, bitcasted_operand, sign_mask_splat, ""); - return LLVMBuildBitCast(g->builder, result, operand_type->llvm_type, ""); -} - -static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst *operand, bool wrapping) { - LLVMValueRef llvm_operand = ir_llvm_value(g, operand); - ZigType *operand_type = operand->value->type; - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return gen_soft_float_neg(g, operand_type, llvm_operand); - } - - if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, inst)); - return LLVMBuildFNeg(g->builder, llvm_operand, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (wrapping) { - return LLVMBuildNeg(g->builder, llvm_operand, ""); - } else if (ir_want_runtime_safety(g, inst)) { - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(llvm_operand)); - return gen_overflow_op(g, operand_type, AddSubMulSub, zero, llvm_operand); - } else if (scalar_type->data.integral.is_signed) { - return LLVMBuildNSWNeg(g->builder, llvm_operand, ""); - } else { - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static LLVMValueRef ir_render_negation(CodeGen *g, Stage1Air *executable, - Stage1AirInstNegation *inst) -{ - return gen_negation(g, &inst->base, inst->operand, inst->wrapping); -} - -static LLVMValueRef ir_render_bool_not(CodeGen *g, Stage1Air *executable, Stage1AirInstBoolNot *instruction) { - LLVMValueRef value = ir_llvm_value(g, instruction->value); - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(value)); - return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); -} - -static void render_decl_var(CodeGen *g, ZigVar *var) { - if (!type_has_bits(g, var->var_type)) - return; - - var->value_ref = ir_llvm_value(g, var->ptr_instruction); - gen_var_debug_decl(g, var); -} - -static LLVMValueRef ir_render_decl_var(CodeGen *g, Stage1Air *executable, Stage1AirInstDeclVar *instruction) { - instruction->var->ptr_instruction = instruction->var_ptr; - instruction->var->did_the_decl_codegen = true; - render_decl_var(g, instruction->var); - return nullptr; -} - -static LLVMValueRef ir_render_load_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstLoadPtr *instruction) -{ - ZigType *child_type = instruction->base.value->type; - if (!type_has_bits(g, child_type)) - return nullptr; - - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - ZigType *ptr_type = instruction->ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - - ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); - if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), - ptr_type->data.pointer.vector_index, false); - uint32_t vec_len = ptr_type->data.pointer.host_int_bytes; - LLVMTypeRef vec_llvm_ty = LLVMVectorType(get_llvm_type(g, child_type), vec_len); - LLVMValueRef loaded_vector = LLVMBuildLoad2(g->builder, vec_llvm_ty, ptr, ""); - return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); - } - - uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes == 0) - return get_handle_value(g, ptr, child_type, ptr_type); - - bool big_endian = g->is_big_endian; - - LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); - LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); - LLVMValueRef containing_int = gen_load_untyped(g, LLVMIntType(host_int_bytes * 8), int_ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - - uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); - ir_assert(host_bit_count == host_int_bytes * 8, &instruction->base); - uint32_t size_in_bits = type_size_bits(g, child_type); - - uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host; - uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset; - - LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); - LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); - - if (handle_is_ptr(g, child_type)) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); - LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc, - LLVMPointerType(same_size_int, 0), ""); - LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr); - return result_loc; - } - - if (child_type->id == ZigTypeIdFloat) { - LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); - LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - return LLVMBuildBitCast(g->builder, truncated_int, get_llvm_type(g, child_type), ""); - } - - return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), ""); -} - -static bool value_is_all_undef_array(CodeGen *g, ZigValue *const_val, size_t len) { - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return true; - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (size_t i = 0; i < len; i += 1) { - if (!value_is_all_undef(g, &const_val->data.x_array.data.s_none.elements[i])) - return false; - } - return true; - } - zig_unreachable(); -} - -static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { - Error err; - if (const_val->special == ConstValSpecialLazy && - (err = ir_resolve_lazy(g, nullptr, const_val))) - codegen_report_errors_and_exit(g); - - switch (const_val->special) { - case ConstValSpecialLazy: - zig_unreachable(); - case ConstValSpecialRuntime: - return false; - case ConstValSpecialUndef: - return true; - case ConstValSpecialStatic: - if (const_val->type->id == ZigTypeIdStruct) { - for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { - TypeStructField *field = const_val->type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, may be uninitialized, - // and should not be inspected. - continue; - } - if (!value_is_all_undef(g, const_val->data.x_struct.fields[i])) - return false; - } - return true; - } else if (const_val->type->id == ZigTypeIdArray) { - return value_is_all_undef_array(g, const_val, const_val->type->data.array.len); - } else if (const_val->type->id == ZigTypeIdVector) { - return value_is_all_undef_array(g, const_val, const_val->type->data.vector.len); - } else { - return false; - } - } - zig_unreachable(); -} - -static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default_value, LLVMValueRef request, - LLVMValueRef a1, LLVMValueRef a2, LLVMValueRef a3, LLVMValueRef a4, LLVMValueRef a5) -{ - if (!target_has_valgrind_support(g->zig_target)) { - return default_value; - } - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - bool asm_has_side_effects = true; - bool asm_is_alignstack = false; - if (g->zig_target->arch == ZigLLVM_x86_64) { - if (g->zig_target->os == OsLinux || target_os_is_darwin(g->zig_target->os) || g->zig_target->os == OsSolaris || - (g->zig_target->os == OsWindows && g->zig_target->abi != ZigLLVM_MSVC)) - { - if (g->cur_fn->valgrind_client_request_array == nullptr) { - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(g->cur_fn->llvm_value); - LLVMValueRef first_inst = LLVMGetFirstInstruction(entry_block); - LLVMPositionBuilderBefore(g->builder, first_inst); - LLVMTypeRef array_type_ref = LLVMArrayType(usize_type_ref, 6); - g->cur_fn->valgrind_client_request_array = LLVMBuildAlloca(g->builder, array_type_ref, ""); - LLVMPositionBuilderAtEnd(g->builder, prev_block); - } - LLVMValueRef array_ptr = g->cur_fn->valgrind_client_request_array; - LLVMValueRef array_elements[] = {request, a1, a2, a3, a4, a5}; - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - for (unsigned i = 0; i < 6; i += 1) { - LLVMValueRef indexes[] = { - zero, - LLVMConstInt(usize_type_ref, i, false), - }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, - LLVMGetAllocatedType(array_ptr), array_ptr, indexes, 2, ""); - LLVMBuildStore(g->builder, array_elements[i], elem_ptr); - } - - Buf *asm_template = buf_create_from_str( - "rolq $$3, %rdi ; rolq $$13, %rdi\n" - "rolq $$61, %rdi ; rolq $$51, %rdi\n" - "xchgq %rbx,%rbx\n" - ); - Buf *asm_constraints = buf_create_from_str( - "={rdx},{rax},0,~{cc},~{memory}" - ); - unsigned input_and_output_count = 2; - LLVMValueRef array_ptr_as_usize = LLVMBuildPtrToInt(g->builder, array_ptr, usize_type_ref, ""); - LLVMValueRef param_values[] = { array_ptr_as_usize, default_value }; - LLVMTypeRef param_types[] = {usize_type_ref, usize_type_ref}; - LLVMTypeRef function_type = LLVMFunctionType(usize_type_ref, param_types, - input_and_output_count, false); - LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(asm_template), buf_len(asm_template), - buf_ptr(asm_constraints), buf_len(asm_constraints), asm_has_side_effects, asm_is_alignstack, - LLVMInlineAsmDialectATT, false); - return LLVMBuildCall2(g->builder, function_type, asm_fn, param_values, input_and_output_count, ""); - } - } - zig_unreachable(); -} - -static void gen_valgrind_undef(CodeGen *g, LLVMValueRef dest_ptr, LLVMValueRef byte_count) { - static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false); - LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false); - LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, ""); - gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero); -} - -static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr) { - assert(type_has_bits(g, value_type)); - - uint64_t ptr_align_bytes = get_ptr_align(g, ptr_type); - assert(ptr_align_bytes > 0); - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type)); - assert(size_bytes > 0); - - if (ptr_type->data.pointer.host_int_bytes == 0) { - // memset uninitialized memory to 0xaa - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef byte_count = LLVMConstInt(usize->llvm_type, size_bytes, false); - ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); - // then tell valgrind that the memory is undefined even though we just memset it - if (g->valgrind_enabled) { - gen_valgrind_undef(g, dest_ptr, byte_count); - } - return; - } - - // This is a pointer into a packed struct, we can't use memset here. - // The jury is still out on what pattern should be written here so clear the - // old value and call it a day. Generating a 0xAA...AA mask for this n-bit - // value is left as an exercise for the (bored) reader. - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, value_type)); - gen_assign_raw(g, ptr, ptr_type, zero); -} - -static LLVMValueRef ir_render_store_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstStorePtr *instruction) { - Error err; - - ZigType *ptr_type = instruction->ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - bool ptr_type_has_bits; - if ((err = type_has_bits2(g, ptr_type, &ptr_type_has_bits))) - codegen_report_errors_and_exit(g); - if (!ptr_type_has_bits) - return nullptr; - if (instruction->ptr->ref_count == 0) { - // In this case, this StorePtr instruction should be elided. Something happened like this: - // var t = true; - // const x = if (t) Num.Two else unreachable; - // The if condition is a runtime value, so the StorePtr for `x = Num.Two` got generated - // (this instruction being rendered) but because of `else unreachable` the result ended - // up being a comptime const value. - return nullptr; - } - - bool have_init_expr = !value_is_all_undef(g, instruction->value->value); - if (have_init_expr) { - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - gen_assign_raw(g, ptr, ptr_type, value); - } else if (ir_want_runtime_safety(g, &instruction->base)) { - gen_undef_init(g, ptr_type, instruction->value->value->type, - ir_llvm_value(g, instruction->ptr)); - } - return nullptr; -} - -static LLVMValueRef ir_render_vector_store_elem(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorStoreElem *instruction) -{ - LLVMValueRef vector_ptr = ir_llvm_value(g, instruction->vector_ptr); - LLVMValueRef index = ir_llvm_value(g, instruction->index); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - LLVMValueRef loaded_vector = gen_load(g, vector_ptr, instruction->vector_ptr->value->type, ""); - LLVMValueRef modified_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, index, ""); - gen_store(g, modified_vector, vector_ptr, instruction->vector_ptr->value->type); - return nullptr; -} - -static LLVMValueRef ir_render_var_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstVarPtr *instruction) { - Error err; - - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - bool ptr_type_has_bits; - if ((err = type_has_bits2(g, ptr_type, &ptr_type_has_bits))) - codegen_report_errors_and_exit(g); - - if (!ptr_type_has_bits) { - return nullptr; - } - - // The extra bitcasts are needed in case the LLVM value is an unnamed - // struct, as it happens when rendering container types with extra alignment - // fields. - if (instruction->base.value->special != ConstValSpecialRuntime) { - return LLVMBuildBitCast(g->builder, ir_llvm_value(g, &instruction->base), - get_llvm_type(g, ptr_type), ""); - } - - ZigVar *var = instruction->var; - assert(var->value_ref); - return LLVMBuildBitCast(g->builder, var->value_ref, - get_llvm_type(g, ptr_type), ""); -} - -static LLVMValueRef ir_render_return_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstReturnPtr *instruction) -{ - if (!type_has_bits(g, instruction->base.value->type)) - return nullptr; - ir_assert(g->cur_ret_ptr != nullptr, &instruction->base); - return g->cur_ret_ptr; -} - -static LLVMValueRef ir_render_elem_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstElemPtr *instruction) { - LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr); - ZigType *array_ptr_type = instruction->array_ptr->value->type; - assert(array_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_type->data.pointer.child_type; - LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index); - assert(subscript_value); - - if (!type_has_bits(g, array_type)) - return nullptr; - - bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on; - - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); - array_type = array_type->data.pointer.child_type; - } - - assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr); - - if (safety_check_on) { - uint64_t extra_len_from_sentinel = (array_type->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = array_type->data.array.len + extra_len_from_sentinel; - LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); - } - if (array_ptr_type->data.pointer.host_int_bytes != 0) { - return array_ptr_ptr; - } - ZigType *child_type = array_type->data.array.child_type; - if (child_type->id == ZigTypeIdStruct && - child_type->data.structure.layout == ContainerLayoutPacked) - { - ZigType *ptr_type = instruction->base.value->type; - size_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes != 0) { - uint32_t size_in_bits = type_size_bits(g, ptr_type->data.pointer.child_type); - LLVMTypeRef ptr_u8_type_ref = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef u8_array_ptr = LLVMBuildBitCast(g->builder, array_ptr, ptr_u8_type_ref, ""); - assert(size_in_bits % 8 == 0); - LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - size_in_bits / 8, false); - LLVMValueRef byte_offset = LLVMBuildNUWMul(g->builder, subscript_value, elem_size_bytes, ""); - LLVMValueRef indices[] = { byte_offset }; - LLVMValueRef elem_byte_ptr = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), - u8_array_ptr, indices, 1, ""); - return LLVMBuildBitCast(g->builder, elem_byte_ptr, LLVMPointerType(get_llvm_type(g, child_type), 0), ""); - } - } - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - subscript_value - }; - return LLVMBuildInBoundsGEP2(g->builder, get_llvm_type(g, array_type), array_ptr, - indices, 2, ""); - } else if (array_type->id == ZigTypeIdPointer) { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - LLVMValueRef indices[] = { subscript_value }; - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, array_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, array_ptr, indices, 1, ""); - } else if (array_type->id == ZigTypeIdStruct) { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - assert(array_type->data.structure.special == StructSpecialSlice); - - ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - if (!type_has_bits(g, ptr_type)) { - if (safety_check_on) { - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, array_ptr); - } - return nullptr; - } - - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - - if (safety_check_on) { - size_t len_index = array_type->data.structure.fields[slice_len_index]->gen_index; - assert(len_index != SIZE_MAX); - LLVMValueRef len_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, array_type), - array_ptr, (unsigned)len_index, ""); - LLVMValueRef len = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_ptr), len_ptr, - 0, false, ""); - LLVMIntPredicate upper_op = (ptr_type->data.pointer.sentinel != nullptr) ? LLVMIntULE : LLVMIntULT; - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, upper_op, len); - } - - size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; - assert(ptr_index != SIZE_MAX); - LLVMValueRef ptr_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, array_type), - array_ptr, (unsigned)ptr_index, ""); - LLVMValueRef ptr = gen_load_untyped(g, - LLVMPointerTypeInContext(LLVMGetGlobalContext(), 0), ptr_ptr, 0, false, ""); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, ptr, &subscript_value, 1, ""); - } else if (array_type->id == ZigTypeIdVector) { - return array_ptr_ptr; - } else { - zig_unreachable(); - } -} - -static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMTypeRef new_stack_llvm_ty, - LLVMValueRef new_stack) -{ - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, new_stack_llvm_ty, new_stack, (unsigned)slice_ptr_index, ""); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, new_stack_llvm_ty, new_stack, (unsigned)slice_len_index, ""); - - LLVMValueRef ptr_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - LLVMValueRef len_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - - LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), ""); - LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, ""); - const unsigned alignment_factor = ZigLLVMDataLayoutGetStackAlignment(g->target_data_ref); - LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), alignment_factor, false); - LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, ""); - return LLVMBuildNUWSub(g->builder, end_addr, align_adj, ""); -} - -static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) { - LLVMValueRef write_register_fn_val = get_write_register_fn_val(g); - - if (g->sp_md_node == nullptr) { - Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(g->zig_target->arch)); - LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1); - g->sp_md_node = LLVMMDNode(&str_node, 1); - } - - LLVMValueRef params[] = { - g->sp_md_node, - aligned_end_addr, - }; - - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(write_register_fn_val), write_register_fn_val, params, 2, ""); -} - -static void render_async_spills(CodeGen *g) { - ZigType *fn_type = g->cur_fn->type_entry; - ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base); - - CalcLLVMFieldIndex arg_calc = {0}; - frame_index_arg_calc(g, &arg_calc, fn_type->data.fn.fn_type_id.return_type); - for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) { - ZigVar *var = g->cur_fn->variable_list.at(var_i); - - if (!type_has_bits(g, var->var_type)) { - continue; - } - if (ir_get_var_is_comptime(var)) - continue; - switch (type_requires_comptime(g, var->var_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeYes: - continue; - case ReqCompTimeNo: - break; - } - if (var->src_arg_index == SIZE_MAX) { - continue; - } - - calc_llvm_field_index_add(g, &arg_calc, var->var_type); - var->value_ref = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, arg_calc.field_index - 1, var->name); - if (var->decl_node) { - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); - gen_var_debug_decl(g, var); - } - } - - ZigType *frame_type = g->cur_fn->frame_type->data.frame.locals_struct; - - for (size_t alloca_i = 0; alloca_i < g->cur_fn->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = g->cur_fn->alloca_gen_list.at(alloca_i); - if (instruction->field_index == SIZE_MAX) - continue; - - size_t gen_index = frame_type->data.structure.fields[instruction->field_index]->gen_index; - instruction->base.llvm_value = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, gen_index, - instruction->name_hint); - } -} - -static void render_async_var_decls(CodeGen *g, Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdFnDef: - return; - case ScopeIdVarDecl: { - ZigVar *var = reinterpret_cast(scope)->var; - if (var->did_the_decl_codegen) { - render_decl_var(g, var); - } - } - ZIG_FALLTHROUGH; - - case ScopeIdDecls: - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - } - } -} - -static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { - assert(g->need_frame_size_prefix_data); - LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0); - LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); - LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true); - LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP2(g->builder, usize_llvm_type, casted_fn_val, &negative_one, 1, ""); - LLVMValueRef load_inst = LLVMBuildLoad2(g->builder, usize_llvm_type, prefix_ptr, ""); - - // Some architectures (e.g SPARCv9) has different alignment requirements between a - // function/usize pointer and also require all loads to be aligned. - // On those architectures, not explicitly setting the alignment will lead into @frameSize - // generating usize-aligned load instruction that could crash if the function pointer - // happens to be not usize-aligned. - LLVMSetAlignment(load_inst, 1); - return load_inst; -} - -static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMTypeRef stack_trace_llvm_ty = get_llvm_type(g, get_stack_trace_type(g)); - - LLVMValueRef index_ptr = LLVMBuildStructGEP2(g->builder, stack_trace_llvm_ty, trace_field_ptr, 0, ""); - LLVMBuildStore(g->builder, zero, index_ptr); - - LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP2(g->builder, stack_trace_llvm_ty, trace_field_ptr, 1, ""); - LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_slice_ptr), - addrs_slice_ptr, slice_ptr_index, ""); - LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) }; - LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_field_ptr), addrs_field_ptr, indices, 2, ""); - LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr); - - LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_slice_ptr), - addrs_slice_ptr, slice_len_index, ""); - LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr); -} - -static LLVMValueRef ir_render_call(CodeGen *g, Stage1Air *executable, Stage1AirInstCall *instruction) { - Error err; - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - LLVMValueRef fn_val; - LLVMTypeRef fn_llvm_ty; - ZigType *fn_type; - bool callee_is_async; - if (instruction->fn_entry) { - fn_val = fn_llvm_value(g, instruction->fn_entry); - fn_type = instruction->fn_entry->type_entry; - callee_is_async = fn_is_async(instruction->fn_entry); - fn_llvm_ty = LLVMGlobalGetValueType(fn_val); - } else { - assert(instruction->fn_ref); - fn_val = ir_llvm_value(g, instruction->fn_ref); - fn_type = instruction->fn_ref->value->type; - callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync; - fn_llvm_ty = fn_type->data.fn.raw_type_ref; - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - - ZigType *src_return_type = fn_type_id->return_type; - bool ret_has_bits = type_has_bits(g, src_return_type); - - CallingConvention cc = fn_type->data.fn.fn_type_id.cc; - - bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id); - bool prefix_arg_err_ret_stack = codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type); - bool is_var_args = fn_type_id->is_var_args; - ZigList gen_param_values = {}; - ZigList gen_param_types = {}; - LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - bool need_frame_ptr_ptr_spill = false; - ZigType *anyframe_type = nullptr; - LLVMValueRef frame_result_loc_uncasted = nullptr; - LLVMValueRef frame_result_loc; - LLVMTypeRef frame_struct_llvm_ty; - LLVMValueRef awaiter_init_val; - LLVMValueRef ret_ptr; - if (callee_is_async) { - if (instruction->new_stack == nullptr) { - if (instruction->modifier == CallModifierAsync) { - frame_result_loc = result_loc; - if (result_loc != nullptr) { - ir_assert(instruction->result_loc->value->type->id == ZigTypeIdPointer, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->result_loc->value->type->data.pointer.child_type); - } else { - frame_struct_llvm_ty = nullptr; - } - } else { - ir_assert(instruction->frame_result_loc != nullptr, &instruction->base); - frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); - ir_assert(instruction->fn_entry != nullptr, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->fn_entry->frame_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - LLVMPointerType(frame_struct_llvm_ty, 0), ""); - } - } else { - if (instruction->new_stack->value->type->id == ZigTypeIdPointer && - instruction->new_stack->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - frame_result_loc = ir_llvm_value(g, instruction->new_stack); - frame_struct_llvm_ty = get_llvm_type(g, instruction->new_stack->value->type->data.pointer.child_type); - } else { - LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); - LLVMTypeRef frame_slice_llvm_ty = get_llvm_type(g, instruction->new_stack->value->type); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef given_len_ptr = LLVMBuildStructGEP2(g->builder, - frame_slice_llvm_ty, frame_slice_ptr, slice_len_index, ""); - LLVMValueRef given_frame_len = LLVMBuildLoad2(g->builder, usize_type_ref, given_len_ptr, ""); - LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk"); - - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, ""); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdFrameTooSmall); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - need_frame_ptr_ptr_spill = true; - LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_slice_llvm_ty, - frame_slice_ptr, slice_ptr_index, ""); - LLVMValueRef frame_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(frame_ptr_ptr), frame_ptr_ptr, ""); - if (instruction->fn_entry == nullptr) { - anyframe_type = get_any_frame_type(g, src_return_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); - frame_struct_llvm_ty = anyframe_type->data.any_frame.struct_llvm_ty; - } else { - ZigType *frame_type = get_fn_frame_type(g, instruction->fn_entry); - if ((err = type_resolve(g, frame_type, ResolveStatusLLVMFull))) - codegen_report_errors_and_exit(g); - ZigType *ptr_frame_type = get_pointer_to_type(g, frame_type, false); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, - get_llvm_type(g, ptr_frame_type), ""); - frame_struct_llvm_ty = get_llvm_type(g, frame_type); - } - } - } - if (instruction->modifier == CallModifierAsync) { - if (instruction->new_stack == nullptr) { - awaiter_init_val = zero; - - if (ret_has_bits) { - // Use the result location which is inside the frame if this is an async call. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - } - } else { - awaiter_init_val = zero; - - if (ret_has_bits) { - if (result_loc != nullptr) { - // Use the result location provided to the @asyncCall builtin - ret_ptr = result_loc; - } else { - // no result location provided to @asyncCall - use the one inside the frame. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - } - } - } - - // even if prefix_arg_err_ret_stack is true, let the async function do its own - // initialization. - } else { - if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) { - // Async function called as a normal function, and calling function is not async. - // This is allowed because it was called with `nosuspend` which asserts that it will - // never suspend. - awaiter_init_val = zero; - } else { - // async function called as a normal function - awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer - } - if (ret_has_bits) { - if (result_loc == nullptr) { - // return type is a scalar, but we still need a pointer to it. Use the async fn frame. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 2, ""); - } else { - // Use the call instruction's result location. - ret_ptr = result_loc; - } - - // Store a zero in the awaiter's result ptr to indicate we do not need a copy made. - LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 1, ""); - LLVMValueRef zero_ptr = LLVMConstNull(ZigLLVMGetGEPResultElementType(awaiter_ret_ptr)); - LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr); - } - - if (prefix_arg_err_ret_stack) { - LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - frame_index_trace_arg(g, src_return_type) + 1, ""); - bool is_llvm_alloca; - LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, - &is_llvm_alloca); - LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); - } - } - - assert(frame_result_loc != nullptr); - - LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_fn_ptr_index, ""); - LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val, - LLVMPointerTypeInContext(LLVMGetGlobalContext(), 0), ""); - LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr); - - LLVMValueRef resume_index_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_resume_index, ""); - LLVMBuildStore(g->builder, zero, resume_index_ptr); - - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_awaiter_index, ""); - LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); - - if (ret_has_bits) { - LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start, ""); - LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); - } - } else if (instruction->modifier == CallModifierAsync) { - // Async call of blocking function - if (instruction->new_stack != nullptr) { - zig_panic("TODO @asyncCall of non-async function"); - } - frame_result_loc = result_loc; - if (result_loc != nullptr) { - ir_assert(instruction->result_loc->value->type->id == ZigTypeIdPointer, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->result_loc->value->type->data.pointer.child_type); - } else { - frame_struct_llvm_ty = nullptr; - } - awaiter_init_val = LLVMConstAllOnes(usize_type_ref); - - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_awaiter_index, ""); - LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); - - if (ret_has_bits) { - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 2, ""); - LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start, ""); - LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); - - if (first_arg_ret) { - gen_param_values.append(ret_ptr); - } - if (prefix_arg_err_ret_stack) { - // Set up the callee stack trace pointer pointing into the frame. - // Then we have to wire up the StackTrace pointers. - // Await is responsible for merging error return traces. - uint32_t trace_field_index_start = frame_index_trace_arg(g, src_return_type); - LLVMValueRef callee_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start, ""); - LLVMValueRef trace_field_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start + 2, ""); - LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start + 3, ""); - - LLVMBuildStore(g->builder, trace_field_ptr, callee_trace_ptr_ptr); - - gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr); - - bool is_llvm_alloca; - gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca)); - } - } - } else { - if (first_arg_ret) { - gen_param_values.append(result_loc); - } - if (prefix_arg_err_ret_stack) { - bool is_llvm_alloca; - gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca)); - } - } - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdCall; - fn_walk.data.call.inst = instruction; - fn_walk.data.call.is_var_args = is_var_args; - fn_walk.data.call.gen_param_values = &gen_param_values; - fn_walk.data.call.gen_param_types = &gen_param_types; - walk_function_params(g, fn_type, &fn_walk); - - ZigLLVM_CallAttr call_attr; - switch (instruction->modifier) { - case CallModifierBuiltin: - case CallModifierCompileTime: - zig_unreachable(); - case CallModifierNone: - case CallModifierNoSuspend: - case CallModifierAsync: - call_attr = ZigLLVM_CallAttrAuto; - break; - case CallModifierNeverTail: - call_attr = ZigLLVM_CallAttrNeverTail; - break; - case CallModifierNeverInline: - call_attr = ZigLLVM_CallAttrNeverInline; - break; - case CallModifierAlwaysTail: - call_attr = ZigLLVM_CallAttrAlwaysTail; - break; - case CallModifierAlwaysInline: - ir_assert(instruction->fn_entry != nullptr, &instruction->base); - call_attr = ZigLLVM_CallAttrAlwaysInline; - break; - } - - ZigLLVM_CallingConv llvm_cc = get_llvm_cc(g, cc); - LLVMValueRef result; - - if (callee_is_async) { - CalcLLVMFieldIndex arg_calc_start = {0}; - frame_index_arg_calc(g, &arg_calc_start, fn_type->data.fn.fn_type_id.return_type); - - LLVMValueRef casted_frame; - LLVMTypeRef casted_frame_llvm_ty; - if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) { - // We need the frame type to be a pointer to a struct that includes the args - - // Count ahead to determine how many llvm struct fields we need. - CalcLLVMFieldIndex arg_calc = arg_calc_start; - for (size_t i = 0; i < gen_param_types.length; i += 1) { - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(i)); - } - size_t field_count = arg_calc.field_index; - - LLVMTypeRef *field_types = heap::c_allocator.allocate_nonzero(field_count); - LLVMGetStructElementTypes(frame_struct_llvm_ty, field_types); - assert(LLVMCountStructElementTypes(frame_struct_llvm_ty) == arg_calc_start.field_index); - - arg_calc = arg_calc_start; - for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { - CalcLLVMFieldIndex prev = arg_calc; - // Use the declared argument type and not the value one to be - // consistent with the assignment operation below. - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i)); - field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i)); - if (arg_calc.field_index - prev.field_index > 1) { - // Padding field - uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size; - LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes); - field_types[arg_calc.field_index - 2] = pad_llvm_type; - } - } - LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false); - heap::c_allocator.deallocate(field_types, field_count); - LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0); - - casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, ""); - casted_frame_llvm_ty = frame_with_args_type; - } else { - casted_frame = frame_result_loc; - casted_frame_llvm_ty = frame_struct_llvm_ty; - } - - CalcLLVMFieldIndex arg_calc = arg_calc_start; - for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i)); - LLVMValueRef arg_ptr = LLVMBuildStructGEP2(g->builder, casted_frame_llvm_ty, casted_frame, arg_calc.field_index - 1, ""); - gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true), - gen_param_values.at(arg_i)); - } - gen_param_types.deinit(); - - if (instruction->modifier == CallModifierAsync) { - gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - if (instruction->new_stack != nullptr) { - return LLVMBuildBitCast(g->builder, frame_result_loc, - get_llvm_type(g, instruction->base.value->type), ""); - } - return nullptr; - } else if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) { - gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_awaiter_index, ""); - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, - all_ones, LLVMAtomicOrderingRelease); - LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, prev_val, all_ones, ""); - - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendPanic"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendOk"); - LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); - - // The async function suspended, but this nosuspend call asserted it wouldn't. - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdBadNoSuspendCall); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - ZigType *result_type = instruction->base.value->type; - ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); - return gen_await_early_return(g, &instruction->base, - frame_struct_llvm_ty, frame_result_loc, - result_type, ptr_result_type, result_loc, true); - } else { - ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true); - - LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume"); - - LLVMValueRef call_inst = gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - set_tail_call_if_appropriate(g, call_inst); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, call_bb); - gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); - render_async_var_decls(g, instruction->base.scope); - - if (!type_has_bits(g, src_return_type)) - return nullptr; - - if (result_loc != nullptr) { - if (instruction->result_loc->id == Stage1AirInstIdReturnPtr) { - instruction->base.spill = nullptr; - return g->cur_ret_ptr; - } else { - return get_handle_value(g, result_loc, src_return_type, ptr_result_type); - } - } - - if (need_frame_ptr_ptr_spill) { - LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); - LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, instruction->new_stack->value->type), - frame_slice_ptr, slice_ptr_index, ""); - frame_result_loc_uncasted = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(frame_ptr_ptr), frame_ptr_ptr, ""); - } - if (frame_result_loc_uncasted != nullptr) { - if (instruction->fn_entry != nullptr) { - frame_struct_llvm_ty = get_llvm_type(g, instruction->fn_entry->frame_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - LLVMPointerType(frame_struct_llvm_ty, 0), ""); - } else { - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - get_llvm_type(g, anyframe_type), ""); - frame_struct_llvm_ty = anyframe_type->data.any_frame.struct_llvm_ty; - } - } - - LLVMValueRef result_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - return LLVMBuildLoad2(g->builder, get_llvm_type(g, src_return_type), result_ptr, ""); - } - } else { - gen_param_types.deinit(); - } - - if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { - result = ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, - gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); - } else if (instruction->modifier == CallModifierAsync) { - zig_panic("TODO @asyncCall of non-async function"); - } else { - LLVMValueRef new_stack_addr = get_new_stack_addr(g, - get_llvm_type(g, instruction->new_stack->value->type), - ir_llvm_value(g, instruction->new_stack)); - LLVMValueRef old_stack_ref; - if (src_return_type->id != ZigTypeIdUnreachable) { - LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); - old_stack_ref = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(stacksave_fn_val), stacksave_fn_val, nullptr, 0, ""); - } - gen_set_stack_pointer(g, new_stack_addr); - result = ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, - gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); - if (src_return_type->id != ZigTypeIdUnreachable) { - LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(stackrestore_fn_val), stackrestore_fn_val, &old_stack_ref, 1, ""); - } - } - - if (src_return_type->id == ZigTypeIdUnreachable) { - return LLVMBuildUnreachable(g->builder); - } else if (!ret_has_bits) { - return nullptr; - } else if (first_arg_ret) { - ZigLLVMSetCallSret(result, get_llvm_type(g, src_return_type)); - return result_loc; - } else if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, src_return_type); - LLVMTypeRef abi_type_ptr = LLVMPointerType(abi_type, 0); - LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, result_loc, abi_type_ptr, ""); - LLVMBuildStore(g->builder, result, bitcast); - return result_loc; - } else if (handle_is_ptr(g, src_return_type)) { - LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); - LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value->type)); - return result_loc; - } else if (!callee_is_async && instruction->modifier == CallModifierAsync) { - LLVMBuildStore(g->builder, result, ret_ptr); - return result_loc; - } else { - return result; - } -} - -static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstStructFieldPtr *instruction) -{ - Error err; - - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - LLVMValueRef struct_ptr = ir_llvm_value(g, instruction->struct_ptr); - // not necessarily a pointer. could be ZigTypeIdStruct - ZigType *struct_ptr_type = instruction->struct_ptr->value->type; - TypeStructField *field = instruction->field; - - if (!type_has_bits(g, field->type_entry)) - return nullptr; - - if (struct_ptr_type->id == ZigTypeIdPointer && - struct_ptr_type->data.pointer.host_int_bytes != 0) - { - return struct_ptr; - } - - ZigType *struct_type; - if (struct_ptr_type->id == ZigTypeIdPointer) { - if (struct_ptr_type->data.pointer.inferred_struct_field != nullptr) { - struct_type = struct_ptr_type->data.pointer.inferred_struct_field->inferred_struct_type; - } else { - struct_type = struct_ptr_type->data.pointer.child_type; - } - } else { - struct_type = struct_ptr_type; - } - - if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) - codegen_report_errors_and_exit(g); - - ir_assert(field->gen_index != SIZE_MAX, &instruction->base); - LLVMValueRef field_ptr_val = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, struct_type), struct_ptr, (unsigned)field->gen_index, ""); - ZigType *res_type = instruction->base.value->type; - ir_assert(res_type->id == ZigTypeIdPointer, &instruction->base); - if (res_type->data.pointer.host_int_bytes != 0) { - // We generate packed structs with get_llvm_type_of_n_bytes, which is - // u8 for 1 byte or [n]u8 for multiple bytes. But the pointer to the type - // is supposed to be a pointer to the integer. So we bitcast it here. - LLVMTypeRef int_elem_type = LLVMIntType(8*res_type->data.pointer.host_int_bytes); - LLVMTypeRef integer_ptr_type = LLVMPointerType(int_elem_type, 0); - return LLVMBuildBitCast(g->builder, field_ptr_val, integer_ptr_type, ""); - } - return field_ptr_val; -} - -static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnionFieldPtr *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *union_ptr_type = instruction->union_ptr->value->type; - assert(union_ptr_type->id == ZigTypeIdPointer); - ZigType *union_type = union_ptr_type->data.pointer.child_type; - assert(union_type->id == ZigTypeIdUnion); - - TypeUnionField *field = instruction->field; - - if (!type_has_bits(g, field->type_entry)) { - ZigType *tag_type = union_type->data.unionation.tag_type; - if (!instruction->initializing || tag_type == nullptr || !type_has_bits(g, tag_type)) - return nullptr; - - // The field has no bits but we still have to change the discriminant - // value here - LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); - - LLVMTypeRef tag_type_ref = get_llvm_type(g, tag_type); - LLVMValueRef tag_field_ptr = nullptr; - if (union_type->data.unionation.gen_field_count == 0) { - assert(union_type->data.unionation.gen_tag_index == SIZE_MAX); - // The whole union is collapsed into the discriminant - tag_field_ptr = LLVMBuildBitCast(g->builder, union_ptr, - LLVMPointerType(tag_type_ref, 0), ""); - } else { - assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); - tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - } - - LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, - &field->enum_field->value); - assert(tag_field_ptr != nullptr); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - - return nullptr; - } - - LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); - LLVMTypeRef field_type_ref = LLVMPointerType(get_llvm_type(g, field->type_entry), 0); - - if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { - LLVMValueRef union_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), union_ptr, 0, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); - return bitcasted_union_field_ptr; - } - - if (instruction->initializing) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &field->enum_field->value); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - } else if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - LLVMValueRef tag_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(tag_field_ptr), - tag_field_ptr, 0, false, ""); - - - LLVMValueRef expected_tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &field->enum_field->value); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); - LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, ""); - LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdBadUnionField); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - LLVMValueRef union_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_union_index, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); - return bitcasted_union_field_ptr; -} - -static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { - const char *ptr = buf_ptr(src_template) + tok->start + 2; - size_t len = tok->end - tok->start - 2; - size_t result = 0; - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { - return result; - } - } - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { - return result; - } - } - return SIZE_MAX; -} - -static LLVMValueRef ir_render_asm_gen(CodeGen *g, Stage1Air *executable, Stage1AirInstAsm *instruction) { - AstNode *asm_node = instruction->base.source_node; - assert(asm_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr; - - Buf *src_template = instruction->asm_template; - - Buf llvm_template = BUF_INIT; - buf_resize(&llvm_template, 0); - - for (size_t token_i = 0; token_i < instruction->token_list_len; token_i += 1) { - AsmToken *asm_token = &instruction->token_list[token_i]; - switch (asm_token->id) { - case AsmTokenIdTemplate: - for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) { - uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset)); - if (c == '$') { - buf_append_str(&llvm_template, "$$"); - } else { - buf_append_char(&llvm_template, c); - } - } - break; - case AsmTokenIdPercent: - buf_append_char(&llvm_template, '%'); - break; - case AsmTokenIdVar: - { - size_t index = find_asm_index(g, asm_node, asm_token, src_template); - assert(index < SIZE_MAX); - buf_appendf(&llvm_template, "$%" ZIG_PRI_usize "", index); - break; - } - case AsmTokenIdUniqueId: - buf_append_str(&llvm_template, "${:uid}"); - break; - } - } - - Buf constraint_buf = BUF_INIT; - buf_resize(&constraint_buf, 0); - - assert(instruction->return_count == 0 || instruction->return_count == 1); - - size_t total_constraint_count = asm_expr->output_list.length + - asm_expr->input_list.length + - asm_expr->clobber_list.length; - size_t input_and_output_count = asm_expr->output_list.length + - asm_expr->input_list.length - - instruction->return_count; - size_t total_index = 0; - size_t param_index = 0; - LLVMTypeRef *param_types = heap::c_allocator.allocate(input_and_output_count); - LLVMValueRef *param_values = heap::c_allocator.allocate(input_and_output_count); - LLVMTypeRef *param_needs_attr = heap::c_allocator.allocate(input_and_output_count); - for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - bool is_return = (asm_output->return_type != nullptr); - assert(*buf_ptr(asm_output->constraint) == '='); - // LLVM uses commas internally to separate different constraints, - // alternative constraints are achieved with pipes. - // We still allow the user to use commas in a way that is similar - // to GCC's inline assembly. - // http://llvm.org/docs/LangRef.html#constraint-codes - buf_replace(asm_output->constraint, ',', '|'); - - if (is_return) { - buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); - } else { - buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1); - ZigVar *variable = instruction->output_vars[i]; - param_needs_attr[param_index] = get_llvm_type(g, variable->var_type); - } - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - - if (!is_return) { - ZigVar *variable = instruction->output_vars[i]; - assert(variable); - param_types[param_index] = LLVMTypeOf(variable->value_ref); - param_values[param_index] = variable->value_ref; - param_index += 1; - } - } - for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - buf_replace(asm_input->constraint, ',', '|'); - Stage1AirInst *ir_input = instruction->input_list[i]; - buf_append_buf(&constraint_buf, asm_input->constraint); - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - - ZigType *const type = ir_input->value->type; - LLVMTypeRef type_ref = get_llvm_type(g, type); - LLVMValueRef value_ref = ir_llvm_value(g, ir_input); - LLVMTypeRef elem_type_ref = nullptr; - // Handle integers of non pot bitsize by widening them. - if (type->id == ZigTypeIdInt) { - const size_t bitsize = type->data.integral.bit_count; - if (bitsize < 8 || !is_power_of_2(bitsize)) { - const bool is_signed = type->data.integral.is_signed; - const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize); - ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize); - type_ref = get_llvm_type(g, wider_type); - value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); - } - } else if (handle_is_ptr(g, type)) { - elem_type_ref = type_ref; - ZigType *gen_type = get_pointer_to_type(g, type, true); - type_ref = get_llvm_type(g, gen_type); - } - - param_types[param_index] = type_ref; - param_values[param_index] = value_ref; - // In the case of indirect inputs, LLVM requires the callsite to have an elementtype() attribute. - if (buf_ptr(asm_input->constraint)[0] == '*') { - param_needs_attr[param_index] = elem_type_ref ? elem_type_ref : - get_llvm_type(g, type->data.pointer.child_type); - } - } - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { - Buf *clobber_buf = asm_expr->clobber_list.at(i); - buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf)); - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - } - - // Add some architecture-specific clobbers. - const char *arch_clobbers = nullptr; - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - arch_clobbers = "~{dirflag},~{fpsr},~{flags}"; - break; - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - arch_clobbers = "~{$1}"; - break; - default: - break; - } - - if (arch_clobbers != nullptr) { - if (buf_len(&constraint_buf)) - buf_append_char(&constraint_buf, ','); - buf_append_str(&constraint_buf, arch_clobbers); - } - - LLVMTypeRef ret_type; - if (instruction->return_count == 0) { - ret_type = LLVMVoidType(); - } else { - ret_type = get_llvm_type(g, instruction->base.value->type); - } - LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false); - - bool is_volatile = instruction->has_side_effects || (asm_expr->output_list.length == 0); - LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template), - buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT, false); - - LLVMValueRef built_call = LLVMBuildCall2(g->builder, function_type, - asm_fn, param_values, (unsigned)input_and_output_count, ""); - - for (size_t i = 0; i < input_and_output_count; i += 1) { - if (param_needs_attr[i] != nullptr) { - LLVMTypeRef elem_ty = param_needs_attr[i]; - ZigLLVMSetCallElemTypeAttr(built_call, i, elem_ty); - } - } - - - - heap::c_allocator.deallocate(param_types, input_and_output_count); - heap::c_allocator.deallocate(param_values, input_and_output_count); - heap::c_allocator.deallocate(param_needs_attr, input_and_output_count); - return built_call; -} - -static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueRef maybe_handle) { - assert(maybe_type->id == ZigTypeIdOptional || - (maybe_type->id == ZigTypeIdPointer && maybe_type->data.pointer.allow_zero)); - - ZigType *child_type = maybe_type->data.maybe.child_type; - if (!type_has_bits(g, child_type)) - return maybe_handle; - - bool is_scalar = !handle_is_ptr(g, maybe_type); - if (is_scalar) - return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), ""); - - LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), maybe_handle, maybe_null_index, ""); - return gen_load_untyped(g, ZigLLVMGetGEPResultElementType(maybe_field_ptr), maybe_field_ptr, 0, false, ""); -} - -static LLVMValueRef ir_render_test_non_null(CodeGen *g, Stage1Air *executable, - Stage1AirInstTestNonNull *instruction) -{ - return gen_non_null_bit(g, instruction->value->value->type, ir_llvm_value(g, instruction->value)); -} - -static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstOptionalUnwrapPtr *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *ptr_type = instruction->base_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *maybe_type = ptr_type->data.pointer.child_type; - assert(maybe_type->id == ZigTypeIdOptional); - ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef base_ptr = ir_llvm_value(g, instruction->base_ptr); - if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef maybe_handle = get_handle_value(g, base_ptr, maybe_type, ptr_type); - LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); - LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - if (!type_has_bits(g, child_type)) { - if (instruction->initializing) { - LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); - gen_store_untyped(g, non_null_bit, base_ptr, 0, false); - } - return nullptr; - } else { - bool is_scalar = !handle_is_ptr(g, maybe_type); - if (is_scalar) { - return base_ptr; - } else { - LLVMValueRef optional_struct_ref = get_handle_value(g, base_ptr, maybe_type, ptr_type); - if (instruction->initializing) { - LLVMValueRef non_null_bit_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), optional_struct_ref, maybe_null_index, ""); - LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); - gen_store_untyped(g, non_null_bit, non_null_bit_ptr, 0, false); - } - return LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), optional_struct_ref, maybe_child_index, ""); - } - } -} - -static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFnId fn_id) { - bool is_vector = expr_type->id == ZigTypeIdVector; - ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; - assert(int_type->id == ZigTypeIdInt); - uint32_t vector_len = is_vector ? expr_type->data.vector.len : 0; - ZigLLVMFnKey key = {}; - const char *fn_name; - uint32_t n_args; - if (fn_id == BuiltinFnIdCtz) { - fn_name = "cttz"; - n_args = 2; - key.id = ZigLLVMFnIdCtz; - key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.ctz.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdClz) { - fn_name = "ctlz"; - n_args = 2; - key.id = ZigLLVMFnIdClz; - key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.clz.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdPopCount) { - fn_name = "ctpop"; - n_args = 1; - key.id = ZigLLVMFnIdPopCount; - key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.pop_count.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdBswap) { - fn_name = "bswap"; - n_args = 1; - key.id = ZigLLVMFnIdBswap; - key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.bswap.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdBitReverse) { - fn_name = "bitreverse"; - n_args = 1; - key.id = ZigLLVMFnIdBitReverse; - key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.bit_reverse.vector_len = vector_len; - } else { - zig_unreachable(); - } - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - char llvm_name[64]; - if (is_vector) - snprintf(llvm_name, sizeof(llvm_name), "llvm.%s.v%" PRIu32 "i%" PRIu32, fn_name, vector_len, int_type->data.integral.bit_count); - else - snprintf(llvm_name, sizeof(llvm_name), "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); - LLVMTypeRef param_types[] = { - get_llvm_type(g, expr_type), - LLVMInt1Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, expr_type), param_types, n_args, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - - g->llvm_fn_table.put(key, fn_val); - - return fn_val; -} - -static LLVMValueRef ir_render_clz(CodeGen *g, Stage1Air *executable, Stage1AirInstClz *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef params[] { - operand, - LLVMConstNull(LLVMInt1Type()), - }; - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_ctz(CodeGen *g, Stage1Air *executable, Stage1AirInstCtz *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef params[] { - operand, - LLVMConstNull(LLVMInt1Type()), - }; - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, Stage1Air *executable, Stage1AirInstShuffleVector *instruction) { - uint64_t len_a = instruction->a->value->type->data.vector.len; - uint64_t len_mask = instruction->mask->value->type->data.vector.len; - - // LLVM uses integers larger than the length of the first array to - // index into the second array. This was deemed unnecessarily fragile - // when changing code, so Zig uses negative numbers to index the - // second vector. These start at -1 and go down, and are easiest to use - // with the ~ operator. Here we convert between the two formats. - Stage1AirInst *mask = instruction->mask; - LLVMValueRef *values = heap::c_allocator.allocate(len_mask); - for (uint64_t i = 0; i < len_mask; i++) { - if (mask->value->data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef) { - values[i] = LLVMGetUndef(LLVMInt32Type()); - } else { - int32_t v = bigint_as_signed(&mask->value->data.x_array.data.s_none.elements[i].data.x_bigint); - uint32_t index_val = (v >= 0) ? (uint32_t)v : (uint32_t)~v + (uint32_t)len_a; - values[i] = LLVMConstInt(LLVMInt32Type(), index_val, false); - } - } - - LLVMValueRef llvm_mask_value = LLVMConstVector(values, len_mask); - heap::c_allocator.deallocate(values, len_mask); - - return LLVMBuildShuffleVector(g->builder, - ir_llvm_value(g, instruction->a), - ir_llvm_value(g, instruction->b), - llvm_mask_value, ""); -} - -static LLVMValueRef ir_render_select(CodeGen *g, Stage1Air *executable, Stage1AirInstSelect *instruction) { - LLVMValueRef pred = ir_llvm_value(g, instruction->pred); - LLVMValueRef a = ir_llvm_value(g, instruction->a); - LLVMValueRef b = ir_llvm_value(g, instruction->b); - return LLVMBuildSelect(g->builder, pred, a, b, ""); -} - -static LLVMValueRef ir_render_splat(CodeGen *g, Stage1Air *executable, Stage1AirInstSplat *instruction) { - ZigType *result_type = instruction->base.value->type; - ir_assert(result_type->id == ZigTypeIdVector, &instruction->base); - uint32_t len = result_type->data.vector.len; - LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value->type), 1); - LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); - LLVMValueRef undef_vector = LLVMGetUndef(op_llvm_type); - LLVMValueRef op_vector = LLVMBuildInsertElement(g->builder, undef_vector, - ir_llvm_value(g, instruction->scalar), LLVMConstInt(LLVMInt32Type(), 0, false), ""); - return LLVMBuildShuffleVector(g->builder, op_vector, undef_vector, LLVMConstNull(mask_llvm_type), ""); -} - -static LLVMValueRef ir_render_pop_count(CodeGen *g, Stage1Air *executable, Stage1AirInstPopCount *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &operand, 1, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_switch_br(CodeGen *g, Stage1Air *executable, Stage1AirInstSwitchBr *instruction) { - ZigType *target_type = instruction->target_value->value->type; - LLVMBasicBlockRef else_block = instruction->else_block->llvm_block; - - LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value); - if (target_type->id == ZigTypeIdPointer) { - const ZigType *usize = g->builtin_types.entry_usize; - target_value = LLVMBuildPtrToInt(g->builder, target_value, usize->llvm_type, ""); - } - - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, - (unsigned)instruction->case_count); - - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1AirInstSwitchBrCase *this_case = &instruction->cases[i]; - - LLVMValueRef case_value = ir_llvm_value(g, this_case->value); - if (target_type->id == ZigTypeIdPointer) { - const ZigType *usize = g->builtin_types.entry_usize; - case_value = LLVMBuildPtrToInt(g->builder, case_value, usize->llvm_type, ""); - } - - LLVMAddCase(switch_instr, case_value, this_case->block->llvm_block); - } - - return nullptr; -} - -static LLVMValueRef ir_render_phi(CodeGen *g, Stage1Air *executable, Stage1AirInstPhi *instruction) { - if (!type_has_bits(g, instruction->base.value->type)) - return nullptr; - - LLVMTypeRef phi_type; - if (handle_is_ptr(g, instruction->base.value->type)) { - phi_type = LLVMPointerType(get_llvm_type(g,instruction->base.value->type), 0); - } else { - phi_type = get_llvm_type(g, instruction->base.value->type); - } - - LLVMValueRef phi = LLVMBuildPhi(g->builder, phi_type, ""); - LLVMValueRef *incoming_values = heap::c_allocator.allocate(instruction->incoming_count); - LLVMBasicBlockRef *incoming_blocks = heap::c_allocator.allocate(instruction->incoming_count); - for (size_t i = 0; i < instruction->incoming_count; i += 1) { - incoming_values[i] = ir_llvm_value(g, instruction->incoming_values[i]); - incoming_blocks[i] = instruction->incoming_blocks[i]->llvm_exit_block; - } - LLVMAddIncoming(phi, incoming_values, incoming_blocks, (unsigned)instruction->incoming_count); - heap::c_allocator.deallocate(incoming_values, instruction->incoming_count); - heap::c_allocator.deallocate(incoming_blocks, instruction->incoming_count); - return phi; -} - -static LLVMValueRef ir_render_ref(CodeGen *g, Stage1Air *executable, Stage1AirInstRef *instruction) { - if (!type_has_bits(g, instruction->base.value->type)) { - return nullptr; - } - if (instruction->operand->id == Stage1AirInstIdCall) { - Stage1AirInstCall *call = reinterpret_cast(instruction->operand); - if (call->result_loc != nullptr) { - return ir_llvm_value(g, call->result_loc); - } - } - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - if (handle_is_ptr(g, instruction->operand->value->type)) { - return value; - } else { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, value, result_loc, 0, false); - return result_loc; - } -} - -static LLVMValueRef ir_render_err_name(CodeGen *g, Stage1Air *executable, Stage1AirInstErrName *instruction) { - assert(g->generate_error_name_table); - assert(g->errors_by_index.length > 0); - - LLVMValueRef err_val = ir_llvm_value(g, instruction->value); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); - LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false); - add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); - } - - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - err_val, - }; - return LLVMBuildInBoundsGEP2(g->builder, - LLVMGlobalGetValueType(g->err_name_table), - g->err_name_table, indices, 2, ""); -} - -static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { - assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.name_function) - return enum_type->data.enumeration.name_function; - - ZigType *u8_ptr_type = get_pointer_to_type_extra2(g, g->builtin_types.entry_u8, false, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false, - VECTOR_INDEX_NONE, nullptr, g->intern.for_zero_byte()); - ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type); - ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; - - LLVMTypeRef tag_int_llvm_type = get_llvm_type(g, tag_int_type); - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0), - &tag_int_llvm_type, 1, false); - - const char *fn_name = get_mangled_name(g, - buf_ptr(buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)))); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - ZigFn *prev_cur_fn = g->cur_fn; - LLVMValueRef prev_cur_fn_val = g->cur_fn_val; - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - g->cur_fn = nullptr; - g->cur_fn_val = fn_val; - - size_t field_count = enum_type->data.enumeration.src_field_count; - LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); - LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); - - - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef array_ptr_indices[] = { - LLVMConstNull(usize->llvm_type), - LLVMConstNull(usize->llvm_type), - }; - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - for (size_t field_i = 0; field_i < field_count; field_i += 1) { - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - - Buf *name = type_enum_field->name; - auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); - if (entry != nullptr) { - continue; - } - - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), false); - LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); - LLVMSetInitializer(str_global, str_init); - LLVMSetLinkage(str_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(str_global, true); - LLVMSetUnnamedAddr(str_global, true); - LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); - - LLVMValueRef fields[] = { - LLVMConstInBoundsGEP2(LLVMGlobalGetValueType(str_global), str_global, array_ptr_indices, 2), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false), - }; - LLVMValueRef slice_init_value = LLVMConstNamedStruct(get_llvm_type(g, u8_slice_type), fields, 2); - - LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), ""); - LLVMSetInitializer(slice_global, slice_init_value); - LLVMSetLinkage(slice_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(slice_global, true); - LLVMSetUnnamedAddr(slice_global, true); - LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value))); - - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name"); - LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type), - &enum_type->data.enumeration.fields[field_i].value); - LLVMAddCase(switch_instr, this_tag_int_value, return_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRet(g->builder, slice_global); - } - occupied_tag_values.deinit(); - - LLVMPositionBuilderAtEnd(g->builder, bad_value_block); - if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) { - gen_safety_crash(g, PanicMsgIdBadEnumValue); - } else { - LLVMBuildUnreachable(g->builder); - } - - g->cur_fn = prev_cur_fn; - g->cur_fn_val = prev_cur_fn_val; - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - enum_type->data.enumeration.name_function = fn_val; - return fn_val; -} - -static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, Stage1Air *executable, - Stage1AirInstTagName *instruction) -{ - ZigType *enum_type = instruction->target->value->type; - assert(enum_type->id == ZigTypeIdEnum); - - LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); - - LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); - return ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(enum_name_function), enum_name_function, - &enum_tag_value, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); -} - -static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstFieldParentPtr *instruction) -{ - ZigType *container_ptr_type = instruction->base.value->type; - assert(container_ptr_type->id == ZigTypeIdPointer); - - ZigType *container_type = container_ptr_type->data.pointer.child_type; - - size_t byte_offset = LLVMOffsetOfElement(g->target_data_ref, - get_llvm_type(g, container_type), instruction->field->gen_index); - - LLVMValueRef field_ptr_val = ir_llvm_value(g, instruction->field_ptr); - - if (byte_offset == 0) { - return LLVMBuildBitCast(g->builder, field_ptr_val, get_llvm_type(g, container_ptr_type), ""); - } else { - ZigType *usize = g->builtin_types.entry_usize; - - LLVMValueRef field_ptr_int = LLVMBuildPtrToInt(g->builder, field_ptr_val, usize->llvm_type, ""); - - LLVMValueRef base_ptr_int = LLVMBuildNUWSub(g->builder, field_ptr_int, - LLVMConstInt(usize->llvm_type, byte_offset, false), ""); - - return LLVMBuildIntToPtr(g->builder, base_ptr_int, get_llvm_type(g, container_ptr_type), ""); - } -} - -static LLVMValueRef ir_render_align_cast(CodeGen *g, Stage1Air *executable, Stage1AirInstAlignCast *instruction) { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - assert(target_val); - - bool want_runtime_safety = ir_want_runtime_safety(g, &instruction->base); - if (!want_runtime_safety) { - return target_val; - } - - ZigType *target_type = instruction->base.value->type; - uint32_t align_bytes; - LLVMValueRef ptr_val; - - if (target_type->id == ZigTypeIdPointer) { - align_bytes = get_ptr_align(g, target_type); - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdFn) { - align_bytes = target_type->data.fn.fn_type_id.alignment; - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdPointer) - { - align_bytes = get_ptr_align(g, target_type->data.maybe.child_type); - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdFn) - { - align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment; - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdStruct && - target_type->data.structure.special == StructSpecialSlice) - { - ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index]->type_entry; - align_bytes = get_ptr_align(g, slice_ptr_type); - - size_t ptr_index = target_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_val_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, target_type), - target_val, (unsigned)ptr_index, ""); - ptr_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_val_ptr), ptr_val_ptr, 0, false, ""); - } else { - zig_unreachable(); - } - - assert(align_bytes != 1); - - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef ptr_as_int_val = LLVMBuildPtrToInt(g->builder, ptr_val, usize->llvm_type, ""); - LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->llvm_type, align_bytes - 1, false); - LLVMValueRef anded_val = LLVMBuildAnd(g->builder, ptr_as_int_val, alignment_minus_1, ""); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, LLVMConstNull(usize->llvm_type), ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastFail"); - - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdIncorrectAlignment); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - - return target_val; -} - -static LLVMValueRef ir_render_error_return_trace(CodeGen *g, Stage1Air *executable, - Stage1AirInstErrorReturnTrace *instruction) -{ - bool is_llvm_alloca; - LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - if (cur_err_ret_trace_val == nullptr) { - return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - return cur_err_ret_trace_val; -} - -static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { - switch (atomic_order) { - case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; - case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic; - case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire; - case AtomicOrderRelease: return LLVMAtomicOrderingRelease; - case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease; - case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent; - } - zig_unreachable(); -} - -static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) { - switch (op) { - case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg; - case AtomicRmwOp_add: - return is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd; - case AtomicRmwOp_sub: - return is_float ? LLVMAtomicRMWBinOpFSub : LLVMAtomicRMWBinOpSub; - case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd; - case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand; - case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr; - case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor; - case AtomicRmwOp_max: - return is_signed ? LLVMAtomicRMWBinOpMax : LLVMAtomicRMWBinOpUMax; - case AtomicRmwOp_min: - return is_signed ? LLVMAtomicRMWBinOpMin : LLVMAtomicRMWBinOpUMin; - } - zig_unreachable(); -} - -static LLVMTypeRef get_atomic_abi_type(CodeGen *g, Stage1AirInst *instruction, bool RMWXchg) { - // If the operand type of an atomic operation is not byte sized we need to - // widen it before using it and then truncate the result. - // RMW exchange of floating-point values is bitcasted to same-sized integer - // types to work around a LLVM deficiency when targeting ARM/AArch64. - - ir_assert(instruction->value->type->id == ZigTypeIdPointer, instruction); - ZigType *operand_type = instruction->value->type->data.pointer.child_type; - if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { - if (operand_type->id == ZigTypeIdEnum) { - operand_type = operand_type->data.enumeration.tag_int_type; - } - auto bit_count = operand_type->data.integral.bit_count; - bool is_signed = operand_type->data.integral.is_signed; - - ir_assert(bit_count != 0, instruction); - if (!is_power_of_2(bit_count) || bit_count % 8) { - return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8)); - } else { - return nullptr; - } - } else if (operand_type->id == ZigTypeIdFloat) { - return RMWXchg ? LLVMIntType(operand_type->abi_size * 8) : nullptr; - } else if (operand_type->id == ZigTypeIdBool) { - return g->builtin_types.entry_u8->llvm_type; - } else { - ir_assert(get_codegen_ptr_type_bail(g, operand_type) != nullptr, instruction); - return nullptr; - } -} - -static LLVMValueRef ir_render_cmpxchg(CodeGen *g, Stage1Air *executable, Stage1AirInstCmpxchg *instruction) { - LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); - LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); - LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); - - ZigType *operand_type = instruction->new_value->value->type; - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating - ptr_val = LLVMBuildBitCast(g->builder, ptr_val, - LLVMPointerType(actual_abi_type, 0), ""); - if (operand_type->data.integral.is_signed) { - cmp_val = LLVMBuildSExt(g->builder, cmp_val, actual_abi_type, ""); - new_val = LLVMBuildSExt(g->builder, new_val, actual_abi_type, ""); - } else { - cmp_val = LLVMBuildZExt(g->builder, cmp_val, actual_abi_type, ""); - new_val = LLVMBuildZExt(g->builder, new_val, actual_abi_type, ""); - } - } - - LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order); - LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order); - - LLVMValueRef result_val = LLVMBuildAtomicCmpXchg(g->builder, ptr_val, cmp_val, new_val, - success_order, failure_order, g->is_single_threaded); - LLVMSetWeak(result_val, instruction->is_weak); - - ZigType *optional_type = instruction->base.value->type; - assert(optional_type->id == ZigTypeIdOptional); - ZigType *child_type = optional_type->data.maybe.child_type; - - if (!handle_is_ptr(g, optional_type)) { - LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (actual_abi_type != nullptr) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); - } - LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); - return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); - } - - // When the cmpxchg is discarded, the result location will have no bits. - if (!type_has_bits(g, instruction->result_loc->value->type)) { - return nullptr; - } - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - ir_assert(result_loc != nullptr, &instruction->base); - ir_assert(type_has_bits(g, child_type), &instruction->base); - - LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (actual_abi_type != nullptr) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); - } - LLVMTypeRef result_loc_struct_llvm_ty = get_llvm_type(g, - instruction->result_loc->value->type->data.pointer.child_type); - LLVMValueRef val_ptr = LLVMBuildStructGEP2(g->builder, - result_loc_struct_llvm_ty, result_loc, maybe_child_index, ""); - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - - LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); - LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP2(g->builder, result_loc_struct_llvm_ty, result_loc, - maybe_null_index, ""); - gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false); - return result_loc; -} - -static LLVMValueRef ir_render_reduced_call(CodeGen *g, LLVMValueRef llvm_fn, LLVMValueRef operand_vector, size_t vector_len, LLVMValueRef accum_init, ZigType *accum_ty) { - LLVMTypeRef llvm_usize_ty = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef llvm_vector_len = LLVMConstInt(llvm_usize_ty, vector_len, false); - LLVMTypeRef llvm_result_ty = LLVMTypeOf(accum_init); - - // Allocate and initialize our mutable variables - LLVMValueRef i_ptr = build_alloca(g, g->builtin_types.entry_usize, "i", 0); - LLVMBuildStore(g->builder, LLVMConstInt(llvm_usize_ty, 0, false), i_ptr); - LLVMValueRef accum_ptr = build_alloca(g, accum_ty, "accum", 0); - LLVMBuildStore(g->builder, accum_init, accum_ptr); - - // Setup the loop - LLVMBasicBlockRef loop = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoop"); - LLVMBasicBlockRef loop_exit = LLVMAppendBasicBlock(g->cur_fn_val, "AfterReduce"); - LLVMBuildBr(g->builder, loop); - { - LLVMPositionBuilderAtEnd(g->builder, loop); - - // while (i < vec.len) - LLVMValueRef i = LLVMBuildLoad2(g->builder, llvm_usize_ty, i_ptr, ""); - LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntULT, i, llvm_vector_len, ""); - LLVMBasicBlockRef loop_then = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoopThen"); - - LLVMBuildCondBr(g->builder, cond, loop_then, loop_exit); - - { - LLVMPositionBuilderAtEnd(g->builder, loop_then); - - // accum = f(accum, vec[i]); - LLVMValueRef accum = LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, ""); - LLVMValueRef element = LLVMBuildExtractElement(g->builder, operand_vector, i, ""); - LLVMValueRef params[] { - accum, - element - }; - LLVMValueRef new_accum = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(llvm_fn), llvm_fn, params, 2, ""); - LLVMBuildStore(g->builder, new_accum, accum_ptr); - - // i += 1 - LLVMValueRef new_i = LLVMBuildAdd(g->builder, i, LLVMConstInt(llvm_usize_ty, 1, false), ""); - LLVMBuildStore(g->builder, new_i, i_ptr); - LLVMBuildBr(g->builder, loop); - } - } - - LLVMPositionBuilderAtEnd(g->builder, loop_exit); - return LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, ""); -} - -static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) { - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - ZigType *value_type = instruction->value->value->type; - assert(value_type->id == ZigTypeIdVector); - ZigType *scalar_type = value_type->data.vector.elem_type; - - bool float_intrinsics_allowed = true; - const char *compiler_rt_type_abbrev = nullptr; - const char *math_float_prefix = nullptr; - const char *math_float_suffix = nullptr; - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - float_intrinsics_allowed = false; - compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(scalar_type); - math_float_prefix = libc_float_prefix(g, scalar_type); - math_float_suffix = libc_float_suffix(g, scalar_type); - } - - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &instruction->base)); - - char fn_name[64]; - ZigValue *init_value = nullptr; - switch (instruction->op) { - case ReduceOp_and: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildAndReduce(g->builder, value); - break; - case ReduceOp_or: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildOrReduce(g->builder, value); - break; - case ReduceOp_xor: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildXorReduce(g->builder, value); - break; - case ReduceOp_min: { - if (scalar_type->id == ZigTypeIdInt) { - const bool is_signed = scalar_type->data.integral.is_signed; - return ZigLLVMBuildIntMinReduce(g->builder, value, is_signed); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - return ZigLLVMBuildFPMinReduce(g->builder, value); - } else { - snprintf(fn_name, sizeof(fn_name), "%sfmin%s", math_float_prefix, math_float_suffix); - init_value = create_const_float(g, scalar_type, NAN); - } - } else zig_unreachable(); - } break; - case ReduceOp_max: { - if (scalar_type->id == ZigTypeIdInt) { - const bool is_signed = scalar_type->data.integral.is_signed; - return ZigLLVMBuildIntMaxReduce(g->builder, value, is_signed); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - return ZigLLVMBuildFPMaxReduce(g->builder, value); - } else { - snprintf(fn_name, sizeof(fn_name), "%sfmax%s", math_float_prefix, math_float_suffix); - init_value = create_const_float(g, scalar_type, NAN); - } - } else zig_unreachable(); - } break; - case ReduceOp_add: { - if (scalar_type->id == ZigTypeIdInt) { - return ZigLLVMBuildAddReduce(g->builder, value); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - LLVMValueRef neutral_value = LLVMConstReal( - get_llvm_type(g, scalar_type), -0.0); - return ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value); - } else { - snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev); - init_value = create_const_float(g, scalar_type, 0.0); - } - } else zig_unreachable(); - } break; - case ReduceOp_mul: { - if (scalar_type->id == ZigTypeIdInt) { - return ZigLLVMBuildMulReduce(g->builder, value); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - LLVMValueRef neutral_value = LLVMConstReal( - get_llvm_type(g, scalar_type), 1.0); - return ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value); - } else { - snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev); - init_value = create_const_float(g, scalar_type, 1.0); - } - } else zig_unreachable(); - } break; - default: - zig_unreachable(); - } - - - LLVMValueRef llvm_init_value = gen_const_val(g, init_value, ""); - uint32_t vector_len = value_type->data.vector.len; - LLVMTypeRef llvm_scalar_type = get_llvm_type(g, scalar_type); - const LLVMValueRef llvm_fn = get_soft_float_fn(g, fn_name, 2, llvm_scalar_type, llvm_scalar_type); - return ir_render_reduced_call(g, llvm_fn, value, vector_len, llvm_init_value, scalar_type); -} - -static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) { - LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering(instruction->order); - LLVMBuildFence(g->builder, atomic_order, false, ""); - return nullptr; -} - -static LLVMValueRef ir_render_truncate(CodeGen *g, Stage1Air *executable, Stage1AirInstTruncate *instruction) { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - ZigType *dest_type = instruction->base.value->type; - ZigType *src_type = instruction->target->value->type; - if (dest_type == src_type) { - // no-op - return target_val; - } if (src_type->data.integral.bit_count == dest_type->data.integral.bit_count) { - return LLVMBuildBitCast(g->builder, target_val, get_llvm_type(g, dest_type), ""); - } else { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return LLVMBuildTrunc(g->builder, target_val, get_llvm_type(g, dest_type), ""); - } -} - -static LLVMValueRef ir_render_memset(CodeGen *g, Stage1Air *executable, Stage1AirInstMemset *instruction) { - LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); - LLVMValueRef len_val = ir_llvm_value(g, instruction->count); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); - - ZigType *ptr_type = instruction->dest_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - - bool val_is_undef = value_is_all_undef(g, instruction->byte->value); - LLVMValueRef fill_char; - if (val_is_undef) { - if (ir_want_runtime_safety_scope(g, instruction->base.scope)) { - fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - } else { - return nullptr; - } - } else { - fill_char = ir_llvm_value(g, instruction->byte); - } - ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, fill_char, len_val, get_ptr_align(g, ptr_type), - ptr_type->data.pointer.is_volatile); - - if (val_is_undef && g->valgrind_enabled) { - gen_valgrind_undef(g, dest_ptr_casted, len_val); - } - return nullptr; -} - -static LLVMValueRef ir_render_memcpy(CodeGen *g, Stage1Air *executable, Stage1AirInstMemcpy *instruction) { - LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); - LLVMValueRef src_ptr = ir_llvm_value(g, instruction->src_ptr); - LLVMValueRef len_val = ir_llvm_value(g, instruction->count); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); - - ZigType *dest_ptr_type = instruction->dest_ptr->value->type; - ZigType *src_ptr_type = instruction->src_ptr->value->type; - - assert(dest_ptr_type->id == ZigTypeIdPointer); - assert(src_ptr_type->id == ZigTypeIdPointer); - - bool is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile); - ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, get_ptr_align(g, dest_ptr_type), - src_ptr_casted, get_ptr_align(g, src_ptr_type), len_val, is_volatile); - return nullptr; -} - -static LLVMValueRef ir_render_wasm_memory_size(CodeGen *g, Stage1Air *executable, Stage1AirInstWasmMemorySize *instruction) { - // TODO adjust for wasm64 - LLVMValueRef param = ir_llvm_value(g, instruction->index); - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_wasm_memory_size(g)), gen_wasm_memory_size(g), ¶m, 1, ""); - return val; -} - -static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable, Stage1AirInstWasmMemoryGrow *instruction) { - // TODO adjust for wasm64 - LLVMValueRef params[] = { - ir_llvm_value(g, instruction->index), - ir_llvm_value(g, instruction->delta), - }; - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_wasm_memory_grow(g)), gen_wasm_memory_grow(g), params, 2, ""); - return val; -} - -static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1AirInstPrefetch *instruction) { - static_assert(PrefetchRwRead == 0, ""); - static_assert(PrefetchRwWrite == 1, ""); - assert(instruction->rw == PrefetchRwRead || instruction->rw == PrefetchRwWrite); - - assert(instruction->locality >= 0 && instruction->locality <= 3); - - static_assert(PrefetchCacheInstruction == 0, ""); - static_assert(PrefetchCacheData == 1, ""); - assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction); - - // LLVM fails during codegen of instruction cache prefetchs for these architectures. - // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target. - // To work around this, simply don't emit llvm.prefetch in this case. - // See https://bugs.llvm.org/show_bug.cgi?id=21037 - if (instruction->cache == PrefetchCacheInstruction) { - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return nullptr; - default: - break; - } - } - - // Another case of the same LLVM bug described above - if (instruction->rw == PrefetchRwWrite && instruction->cache == PrefetchCacheInstruction) { - switch (g->zig_target->arch) { - case ZigLLVM_arm: - return nullptr; - default: - break; - } - - } - - LLVMValueRef params[] = { - LLVMBuildBitCast(g->builder, ir_llvm_value(g, instruction->ptr), LLVMPointerType(LLVMInt8Type(), 0), ""), - LLVMConstInt(LLVMInt32Type(), instruction->rw, false), - LLVMConstInt(LLVMInt32Type(), instruction->locality, false), - LLVMConstInt(LLVMInt32Type(), instruction->cache, false), - }; - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_prefetch(g)), gen_prefetch(g), params, 4, ""); - return val; -} - -static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { - Error err; - - LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); - ZigType *array_ptr_type = instruction->ptr->value->type; - assert(array_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_type->data.pointer.child_type; - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - - bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - - // The result is either a slice or a pointer to an array - ZigType *result_type = instruction->base.value->type; - - // This is not whether the result type has a sentinel, but whether there should be a sentinel check, - // e.g. if they used [a..b :s] syntax. - ZigValue *sentinel = instruction->sentinel; - - LLVMValueRef slice_start_ptr = nullptr; - LLVMValueRef len_value = nullptr; - - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { - if (array_type->id == ZigTypeIdPointer) { - array_type = array_type->data.pointer.child_type; - } - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val; - if (instruction->end) { - end_val = ir_llvm_value(g, instruction->end); - } else { - end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); - } - - if (want_runtime_safety) { - // Safety check: start <= end - if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - } - - // Safety check: the last element of the slice (the sentinel if - // requested) must be inside the array - // XXX: Overflow is not checked here... - const size_t full_len = array_type->data.array.len + - (array_type->data.array.sentinel != nullptr); - LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - full_len, false); - - LLVMValueRef check_end_val = end_val; - if (sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); - } - add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); - } - - bool value_has_bits; - if ((err = type_has_bits2(g, array_type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (value_has_bits) { - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - if (want_runtime_safety && sentinel != nullptr) { - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - end_val, - }; - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, - array_llvm_ty, array_ptr, indices, 2, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - start_val, - }; - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, array_ptr, indices, 2, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.ptr_len != PtrLenSingle); - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val = ir_llvm_value(g, instruction->end); - - if (want_runtime_safety) { - // Safety check: start <= end - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - } - - bool value_has_bits; - if ((err = type_has_bits2(g, array_type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (value_has_bits) { - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, array_type->data.pointer.child_type); - if (want_runtime_safety && sentinel != nullptr) { - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, - array_ptr, &end_val, 1, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, array_ptr, - &start_val, 1, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else if (array_type->id == ZigTypeIdStruct) { - assert(array_type->data.structure.special == StructSpecialSlice); - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - - const size_t gen_len_index = array_type->data.structure.fields[slice_len_index]->gen_index; - assert(gen_len_index != SIZE_MAX); - - LLVMValueRef prev_end = nullptr; - if (!instruction->end || want_runtime_safety) { - LLVMValueRef src_len_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, array_type), array_ptr, gen_len_index, ""); - prev_end = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(src_len_ptr), src_len_ptr, 0, false, ""); - } - - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val; - if (instruction->end) { - end_val = ir_llvm_value(g, instruction->end); - } else { - end_val = prev_end; - } - - ZigType *ptr_field_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - - if (want_runtime_safety) { - assert(prev_end); - // Safety check: start <= end - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - - // Safety check: the sentinel counts as one more element - // XXX: Overflow is not checked here... - LLVMValueRef check_prev_end = prev_end; - if (ptr_field_type->data.pointer.sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_prev_end = LLVMBuildNUWAdd(g->builder, prev_end, usize_one, ""); - } - LLVMValueRef check_end_val = end_val; - if (sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); - } - - add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, check_prev_end); - } - - bool ptr_has_bits; - if ((err = type_has_bits2(g, ptr_field_type, &ptr_has_bits))) - codegen_report_errors_and_exit(g); - - if (ptr_has_bits) { - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_field_type->data.pointer.child_type); - const size_t gen_ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; - assert(gen_ptr_index != SIZE_MAX); - - LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, array_type), array_ptr, gen_ptr_index, ""); - LLVMValueRef src_ptr = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(src_ptr_ptr), - src_ptr_ptr, 0, false, ""); - - if (sentinel != nullptr) { - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, - src_ptr, &end_val, 1, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, src_ptr, &start_val, 1, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else { - zig_unreachable(); - } - - bool result_has_bits; - if ((err = type_has_bits2(g, result_type, &result_has_bits))) - codegen_report_errors_and_exit(g); - - // Nothing to do, we're only interested in the bound checks emitted above - if (!result_has_bits) - return nullptr; - - // The starting pointer for the slice may be null in case of zero-sized - // arrays, the length value is always defined. - assert(len_value != nullptr); - - // The slice decays into a pointer to an array, the size is tracked in the - // type itself - if (result_type->id == ZigTypeIdPointer) { - ir_assert(instruction->result_loc == nullptr, &instruction->base); - LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); - - if (slice_start_ptr != nullptr) { - return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); - } - - return LLVMGetUndef(result_ptr_type); - } - - ir_assert(instruction->result_loc != nullptr, &instruction->base); - // Create a new slice - LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); - - ZigType *slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; - - // The slice may not have a pointer at all if it points to a zero-sized type - const size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; - if (gen_ptr_index != SIZE_MAX) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, result_type), tmp_struct_ptr, gen_ptr_index, ""); - if (slice_start_ptr != nullptr) { - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - } else if (want_runtime_safety) { - gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr); - } else { - gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false); - } - } - - const size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; - assert(gen_len_index != SIZE_MAX); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, result_type), tmp_struct_ptr, gen_len_index, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return tmp_struct_ptr; -} - -static LLVMValueRef get_trap_fn_val(CodeGen *g) { - if (g->trap_fn_val) - return g->trap_fn_val; - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false); - g->trap_fn_val = LLVMAddFunction(g->module, "llvm.debugtrap", fn_type); - assert(LLVMGetIntrinsicID(g->trap_fn_val)); - - return g->trap_fn_val; -} - - -static LLVMValueRef ir_render_breakpoint(CodeGen *g, Stage1Air *executable, Stage1AirInstBreakpoint *instruction) { - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_trap_fn_val(g)), get_trap_fn_val(g), nullptr, 0, ""); - return nullptr; -} - -static LLVMValueRef ir_render_return_address(CodeGen *g, Stage1Air *executable, - Stage1AirInstReturnAddress *instruction) -{ - if ((target_is_wasm(g->zig_target) && g->zig_target->os != OsEmscripten) || target_is_bpf(g->zig_target)) { - // LLVM 13 reports "Non-Emscripten WebAssembly hasn't implemented __builtin_return_address" - // https://github.com/ziglang/zig/issues/11946 - return LLVMConstNull(get_llvm_type(g, instruction->base.value->type)); - } - - LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type); - LLVMValueRef ptr_val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_return_address_fn_val(g)), get_return_address_fn_val(g), &zero, 1, ""); - return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, ""); -} - -static LLVMValueRef get_frame_address_fn_val(CodeGen *g) { - if (g->frame_address_fn_val) - return g->frame_address_fn_val; - - ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type), - &g->builtin_types.entry_i32->llvm_type, 1, false); - g->frame_address_fn_val = LLVMAddFunction(g->module, "llvm.frameaddress.p0", fn_type); - assert(LLVMGetIntrinsicID(g->frame_address_fn_val)); - - return g->frame_address_fn_val; -} - -static LLVMValueRef ir_render_frame_address(CodeGen *g, Stage1Air *executable, - Stage1AirInstFrameAddress *instruction) -{ - LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type); - LLVMValueRef ptr_val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_frame_address_fn_val(g)), get_frame_address_fn_val(g), &zero, 1, ""); - return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, ""); -} - -static LLVMValueRef ir_render_handle(CodeGen *g, Stage1Air *executable, Stage1AirInstFrameHandle *instruction) { - return g->cur_frame_ptr; -} - -static LLVMValueRef render_shl_with_overflow(CodeGen *g, Stage1AirInstOverflowOp *instruction) { - ZigType *int_type = instruction->result_ptr_type; - assert(int_type->id == ZigTypeIdInt); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr); - - LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, instruction->op2->value->type, - instruction->op1->value->type, op2); - - LLVMValueRef result = LLVMBuildShl(g->builder, op1, op2_casted, ""); - LLVMValueRef orig_val; - if (int_type->data.integral.is_signed) { - orig_val = LLVMBuildAShr(g->builder, result, op2_casted, ""); - } else { - orig_val = LLVMBuildLShr(g->builder, result, op2_casted, ""); - } - LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, op1, orig_val, ""); - - gen_store(g, result, ptr_result, instruction->result_ptr->value->type); - - return overflow_bit; -} - -static LLVMValueRef ir_render_overflow_op(CodeGen *g, Stage1Air *executable, Stage1AirInstOverflowOp *instruction) { - AddSubMul add_sub_mul; - switch (instruction->op) { - case IrOverflowOpAdd: - add_sub_mul = AddSubMulAdd; - break; - case IrOverflowOpSub: - add_sub_mul = AddSubMulSub; - break; - case IrOverflowOpMul: - add_sub_mul = AddSubMulMul; - break; - case IrOverflowOpShl: - return render_shl_with_overflow(g, instruction); - } - - ZigType *int_type = instruction->result_ptr_type; - assert(int_type->id == ZigTypeIdInt); - - LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr); - - LLVMValueRef params[] = { - op1, - op2, - }; - - LLVMValueRef result_struct = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - gen_store(g, result, ptr_result, instruction->result_ptr->value->type); - - return overflow_bit; -} - -static LLVMValueRef ir_render_test_err(CodeGen *g, Stage1Air *executable, Stage1AirInstTestErr *instruction) { - ZigType *err_union_type = instruction->err_union->value->type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union); - - LLVMValueRef err_val; - if (type_has_bits(g, payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, err_union_type), err_union_handle, err_union_err_index, ""); - err_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(err_val_ptr), err_val_ptr, 0, false, ""); - } else { - err_val = err_union_handle; - } - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); -} - -static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnwrapErrCode *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *ptr_type = instruction->err_union_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *err_union_type = ptr_type->data.pointer.child_type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); - if (!type_has_bits(g, payload_type)) { - return err_union_ptr; - } else { - // TODO assign undef to the payload - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - return LLVMBuildStructGEP2(g->builder, get_llvm_type(g, err_union_type), err_union_handle, - err_union_err_index, ""); - } -} - -static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnwrapErrPayload *instruction) -{ - Error err; - - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && - g->errors_by_index.length > 1; - - ZigType *ptr_type = instruction->value->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *err_union_type = ptr_type->data.pointer.child_type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - bool value_has_bits; - if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits))) - codegen_report_errors_and_exit(g); - if (!want_safety && !value_has_bits) { - if (instruction->initializing) { - gen_store_untyped(g, zero, err_union_ptr, 0, false); - } - return nullptr; - } - - - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - - if (!type_has_bits(g, err_union_type->data.error_union.err_set_type)) { - return err_union_handle; - } - - LLVMTypeRef err_union_llvm_ty = get_llvm_type(g, err_union_type); - - if (want_safety) { - LLVMValueRef err_val; - if (type_has_bits(g, payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, - err_union_handle, err_union_err_index, ""); - err_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(err_val_ptr), err_val_ptr, 0, false, ""); - } else { - err_val = err_union_handle; - } - LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); - LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); - LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); - - LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_safety_crash_for_err(g, err_val, instruction->base.scope); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (type_has_bits(g, payload_type)) { - if (instruction->initializing) { - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, - err_union_handle, err_union_err_index, ""); - LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - } - return LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, err_union_handle, - err_union_payload_index, ""); - } else { - if (instruction->initializing) { - gen_store_untyped(g, zero, err_union_ptr, 0, false); - } - return nullptr; - } -} - -static LLVMValueRef ir_render_optional_wrap(CodeGen *g, Stage1Air *executable, Stage1AirInstOptionalWrap *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdOptional); - - ZigType *child_type = wanted_type->data.maybe.child_type; - - if (!type_has_bits(g, child_type)) { - LLVMValueRef result = LLVMConstAllOnes(LLVMInt1Type()); - if (instruction->result_loc != nullptr) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, result, result_loc, 0, false); - } - return result; - } - - LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); - if (!handle_is_ptr(g, wanted_type)) { - if (instruction->result_loc != nullptr) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, payload_val, result_loc, 0, false); - } - return payload_val; - } - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMTypeRef result_llvm_struct_ty = get_llvm_type(g, wanted_type); - - LLVMValueRef val_ptr = LLVMBuildStructGEP2(g->builder, result_llvm_struct_ty, result_loc, - maybe_child_index, ""); - // child_type and instruction->value->value->type may differ by constness - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP2(g->builder, result_llvm_struct_ty, result_loc, - maybe_null_index, ""); - gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false); - - return result_loc; -} - -static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, Stage1Air *executable, Stage1AirInstErrWrapCode *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdErrorUnion); - - LLVMValueRef err_val = ir_llvm_value(g, instruction->operand); - - if (!handle_is_ptr(g, wanted_type)) - return err_val; - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, wanted_type), - result_loc, err_union_err_index, ""); - gen_store_untyped(g, err_val, err_tag_ptr, 0, false); - - // TODO store undef to the payload - - return result_loc; -} - -static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, Stage1Air *executable, Stage1AirInstErrWrapPayload *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdErrorUnion); - - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; - - if (!type_has_bits(g, err_set_type)) { - return ir_llvm_value(g, instruction->operand); - } - - LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - - if (!type_has_bits(g, payload_type)) - return ok_err_val; - - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); - LLVMTypeRef result_struct_llvm_ty = get_llvm_type(g, wanted_type); - - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, result_struct_llvm_ty, result_loc, - err_union_err_index, ""); - gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - - LLVMValueRef payload_ptr = LLVMBuildStructGEP2(g->builder, result_struct_llvm_ty, result_loc, - err_union_payload_index, ""); - gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); - - return result_loc; -} - -static LLVMValueRef ir_render_union_tag(CodeGen *g, Stage1Air *executable, Stage1AirInstUnionTag *instruction) { - ZigType *union_type = instruction->value->value->type; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (!type_has_bits(g, tag_type)) - return nullptr; - - LLVMValueRef union_val = ir_llvm_value(g, instruction->value); - if (union_type->data.unionation.gen_field_count == 0) - return union_val; - - assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), union_val, - union_type->data.unionation.gen_tag_index, ""); - ZigType *ptr_type = get_pointer_to_type(g, tag_type, false); - return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); -} - -static LLVMValueRef ir_render_panic(CodeGen *g, Stage1Air *executable, Stage1AirInstPanic *instruction) { - bool is_llvm_alloca; - LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - gen_panic(g, ir_llvm_value(g, instruction->msg), err_ret_trace_val, is_llvm_alloca); - return nullptr; -} - -static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicRmw *instruction) -{ - bool is_signed; - ZigType *operand_type = instruction->operand->value->type; - bool is_float = operand_type->id == ZigTypeIdFloat; - if (operand_type->id == ZigTypeIdInt) { - is_signed = operand_type->data.integral.is_signed; - } else { - is_signed = false; - } - LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->op, is_signed, is_float); - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, - op == LLVMAtomicRMWBinOpXchg); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating or bitcasting. - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(actual_abi_type, 0), ""); - LLVMValueRef casted_operand; - if (is_float) { - casted_operand = LLVMBuildBitCast(g->builder, operand, actual_abi_type, ""); - } else if (operand_type->data.integral.is_signed) { - casted_operand = LLVMBuildSExt(g->builder, operand, actual_abi_type, ""); - } else { - casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, ""); - } - LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, - g->is_single_threaded); - if (is_float) { - return LLVMBuildBitCast(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); - } else { - return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); - } - } - - if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) { - return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded); - } - - // it's a pointer but we need to treat it as an int - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), ""); - LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, ""); - LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, - g->is_single_threaded); - return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); -} - -static LLVMValueRef ir_render_atomic_load(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicLoad *instruction) -{ - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - - ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type; - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating - ptr = LLVMBuildBitCast(g->builder, ptr, LLVMPointerType(actual_abi_type, 0), ""); - LLVMValueRef load_inst = gen_load_untyped(g, actual_abi_type, ptr, - get_ptr_align(g, instruction->ptr->value->type), - instruction->ptr->value->type->data.pointer.is_volatile, ""); - LLVMSetOrdering(load_inst, ordering); - return LLVMBuildTrunc(g->builder, load_inst, get_llvm_type(g, operand_type), ""); - } - LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, ""); - LLVMSetOrdering(load_inst, ordering); - return load_inst; -} - -static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicStore *instruction) -{ - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening - ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(actual_abi_type, 0), ""); - if (instruction->value->value->type->data.integral.is_signed) { - value = LLVMBuildSExt(g->builder, value, actual_abi_type, ""); - } else { - value = LLVMBuildZExt(g->builder, value, actual_abi_type, ""); - } - } - LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type); - LLVMSetOrdering(store_inst, ordering); - return nullptr; -} - -static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - ZigType *operand_type = instruction->operand->value->type; - return gen_float_un_op(g, operand, operand_type, instruction->fn_id); -} - -static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction, ZigType *float_type) { - ZigType *operand_type = instruction->op1->value->type; - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - - const char *fn_name; - if (float_type == g->builtin_types.entry_f16) - fn_name = "__fmah"; - else if (float_type == g->builtin_types.entry_f32) - fn_name = "fmaf"; - else if (float_type == g->builtin_types.entry_f64) - fn_name = "fma"; - else if (float_type == g->builtin_types.entry_f80) - fn_name = "__fmax"; - else if (float_type == g->builtin_types.entry_f128) - fn_name = "fmaq"; - else - zig_unreachable(); - - LLVMTypeRef float_type_ref = float_type->llvm_type; - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); - if (vector_len == 0) { - LLVMValueRef params[3] = { op1, op2, op3 }; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, 3, ""); - } - - LLVMValueRef result = LLVMGetUndef(get_llvm_type(g, instruction->op1->value->type)); - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - - LLVMValueRef params[3] = { - LLVMBuildExtractElement(g->builder, op1, index_value, ""), - LLVMBuildExtractElement(g->builder, op2, index_value, ""), - LLVMBuildExtractElement(g->builder, op3, index_value, ""), - }; - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, 3, ""); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - return result; -} - -static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { - ZigType *operand_type = instruction->op1->value->type; - operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - if ((operand_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (operand_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (operand_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return ir_render_soft_mul_add(g, executable, instruction, operand_type); - } - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); - assert(instruction->base.value->type->id == ZigTypeIdFloat || - instruction->base.value->type->id == ZigTypeIdVector); - LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd); - LLVMValueRef args[3] = { op1, op2, op3 }; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, args, 3, ""); -} - -static LLVMValueRef ir_render_bswap(CodeGen *g, Stage1Air *executable, Stage1AirInstBswap *instruction) { - LLVMValueRef op = ir_llvm_value(g, instruction->op); - ZigType *expr_type = instruction->base.value->type; - bool is_vector = expr_type->id == ZigTypeIdVector; - ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; - assert(int_type->id == ZigTypeIdInt); - if (int_type->data.integral.bit_count % 16 == 0) { - LLVMValueRef fn_val = get_int_builtin_fn(g, expr_type, BuiltinFnIdBswap); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &op, 1, ""); - } - // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate - ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, - int_type->data.integral.bit_count + 8); - LLVMValueRef shift_amt = LLVMConstInt(get_llvm_type(g, extended_type), 8, false); - if (is_vector) { - extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type); - LLVMValueRef *values = heap::c_allocator.allocate_nonzero(expr_type->data.vector.len); - for (uint32_t i = 0; i < expr_type->data.vector.len; i += 1) { - values[i] = shift_amt; - } - shift_amt = LLVMConstVector(values, expr_type->data.vector.len); - heap::c_allocator.deallocate(values, expr_type->data.vector.len); - } - // aabbcc - LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); - // 00aabbcc - LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); - LLVMValueRef swapped = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &extended, 1, ""); - // ccbbaa00 - LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, shift_amt, ""); - // 00ccbbaa - return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); -} - -static LLVMValueRef ir_render_extern(CodeGen *g, Stage1Air *executable, - Stage1AirInstExtern *instruction) -{ - ZigType *expr_type = instruction->base.value->type; - assert(get_src_ptr_type(expr_type)); - - const char *symbol_name = buf_ptr(instruction->name); - const LLVMLinkage linkage = to_llvm_linkage(instruction->linkage, true); - - LLVMValueRef global_value = LLVMGetNamedGlobal(g->module, symbol_name); - if (global_value == nullptr) { - global_value = LLVMAddGlobal(g->module, get_llvm_type(g, expr_type), symbol_name); - LLVMSetLinkage(global_value, linkage); - LLVMSetGlobalConstant(global_value, true); - if (instruction->is_thread_local) - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } else if (LLVMGetLinkage(global_value) != linkage) { - // XXX: Handle this case better! - zig_panic("duplicate extern symbol"); - } - - return LLVMBuildBitCast(g->builder, global_value, get_llvm_type(g, expr_type), ""); -} - -static LLVMValueRef ir_render_bit_reverse(CodeGen *g, Stage1Air *executable, Stage1AirInstBitReverse *instruction) { - LLVMValueRef op = ir_llvm_value(g, instruction->op); - ZigType *int_type = instruction->base.value->type; - assert(int_type->id == ZigTypeIdInt); - LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value->type, BuiltinFnIdBitReverse); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &op, 1, ""); -} - -static LLVMValueRef ir_render_vector_to_array(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorToArray *instruction) -{ - ZigType *array_type = instruction->base.value->type; - assert(array_type->id == ZigTypeIdArray); - assert(handle_is_ptr(g, array_type)); - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - - ZigType *elem_type = array_type->data.array.child_type; - bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; - if (bitcast_ok) { - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, - LLVMPointerType(get_llvm_type(g, instruction->vector->value->type), 0), ""); - uint32_t alignment = get_ptr_align(g, instruction->result_loc->value->type); - gen_store_untyped(g, vector, casted_ptr, alignment, false); - } else { - // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast - // will not work, and we fall back to extractelement. - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef u32_type_ref = LLVMInt32Type(); - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - for (uintptr_t i = 0; i < instruction->vector->value->type->data.vector.len; i++) { - LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); - LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); - LLVMValueRef indexes[] = { zero, index_usize }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, result_loc, indexes, 2, ""); - LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector, index_u32, ""); - LLVMBuildStore(g->builder, elem, elem_ptr); - } - } - return result_loc; -} - -static LLVMValueRef ir_render_array_to_vector(CodeGen *g, Stage1Air *executable, - Stage1AirInstArrayToVector *instruction) -{ - ZigType *vector_type = instruction->base.value->type; - assert(vector_type->id == ZigTypeIdVector); - assert(!handle_is_ptr(g, vector_type)); - LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); - LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); - - ZigType *elem_type = vector_type->data.vector.elem_type; - bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; - ZigType *array_type = instruction->array->value->type; - ir_assert(array_type->id == ZigTypeIdArray, &instruction->base); - if (bitcast_ok) { - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, - LLVMPointerType(vector_type_ref, 0), ""); - uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type); - return gen_load_untyped(g, vector_type_ref, casted_ptr, alignment, false, ""); - } else { - // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast - // will not work, and we fall back to insertelement. - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef u32_type_ref = LLVMInt32Type(); - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - LLVMValueRef vector = LLVMGetUndef(vector_type_ref); - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, elem_type); - for (uintptr_t i = 0; i < instruction->base.value->type->data.vector.len; i++) { - LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); - LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); - LLVMValueRef indexes[] = { zero, index_usize }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, array_ptr, - indexes, 2, ""); - LLVMValueRef elem = LLVMBuildLoad2(g->builder, elem_llvm_ty, elem_ptr, ""); - vector = LLVMBuildInsertElement(g->builder, vector, elem, index_u32, ""); - } - return vector; - } -} - -static LLVMValueRef ir_render_assert_zero(CodeGen *g, Stage1Air *executable, - Stage1AirInstAssertZero *instruction) -{ - LLVMValueRef target = ir_llvm_value(g, instruction->target); - ZigType *int_type = instruction->target->value->type; - if (ir_want_runtime_safety(g, &instruction->base)) { - return gen_assert_zero(g, target, int_type); - } - return nullptr; -} - -static LLVMValueRef ir_render_assert_non_null(CodeGen *g, Stage1Air *executable, - Stage1AirInstAssertNonNull *instruction) -{ - LLVMValueRef target = ir_llvm_value(g, instruction->target); - ZigType *target_type = instruction->target->value->type; - - if (target_type->id == ZigTypeIdPointer) { - assert(target_type->data.pointer.ptr_len == PtrLenC); - LLVMValueRef non_null_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target, - LLVMConstNull(get_llvm_type(g, target_type)), ""); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullOk"); - LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_assertion(g, PanicMsgIdUnwrapOptionalFail, &instruction->base); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } else { - zig_unreachable(); - } - return nullptr; -} - -static LLVMValueRef ir_render_suspend_begin(CodeGen *g, Stage1Air *executable, - Stage1AirInstSuspendBegin *instruction) -{ - if (fn_is_async(g->cur_fn)) { - instruction->resume_bb = gen_suspend_begin(g, "SuspendResume"); - } - return nullptr; -} - -static LLVMValueRef ir_render_suspend_finish(CodeGen *g, Stage1Air *executable, - Stage1AirInstSuspendFinish *instruction) -{ - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - } - render_async_var_decls(g, instruction->base.scope); - return nullptr; -} - -static LLVMValueRef gen_await_early_return(CodeGen *g, Stage1AirInst *source_instr, - LLVMTypeRef target_frame_struct_llvm_ty, LLVMValueRef target_frame_ptr, - ZigType *result_type, ZigType *ptr_result_type, LLVMValueRef result_loc, bool non_async) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef their_result_ptr = nullptr; - if (type_has_bits(g, result_type) && (non_async || result_loc != nullptr)) { - LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP2(g->builder, - target_frame_struct_llvm_ty, target_frame_ptr, frame_ret_start, ""); - their_result_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(their_result_ptr_ptr), their_result_ptr_ptr, ""); - if (result_loc != nullptr) { - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, ""); - bool is_volatile = false; - uint32_t abi_align = get_abi_alignment(g, result_type); - LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false); - ZigLLVMBuildMemCpy(g->builder, - dest_ptr_casted, abi_align, - src_ptr_casted, abi_align, byte_count_val, is_volatile); - } - } - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - target_frame_struct_llvm_ty, target_frame_ptr, - frame_index_trace_arg(g, result_type), ""); - LLVMValueRef src_trace_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(their_trace_ptr_ptr), their_trace_ptr_ptr, ""); - bool is_llvm_alloca; - LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca); - LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(get_merge_err_ret_traces_fn_val(g)), - get_merge_err_ret_traces_fn_val(g), args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - if (non_async && type_has_bits(g, result_type)) { - LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc; - return get_handle_value(g, result_ptr, result_type, ptr_result_type); - } else { - return nullptr; - } -} - -static LLVMValueRef ir_render_await(CodeGen *g, Stage1Air *executable, Stage1AirInstAwait *instruction) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame); - ir_assert(instruction->frame->value->type->id == ZigTypeIdAnyFrame, &instruction->base); - LLVMTypeRef target_frame_llvm_ty = instruction->frame->value->type->data.any_frame.struct_llvm_ty; - ZigType *result_type = instruction->base.value->type; - ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); - - LLVMValueRef result_loc = (instruction->result_loc == nullptr) ? - nullptr : ir_llvm_value(g, instruction->result_loc); - - if (instruction->is_nosuspend || - (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn))) - { - return gen_await_early_return(g, &instruction->base, target_frame_llvm_ty, - target_frame_ptr, result_type, ptr_result_type, result_loc, true); - } - - // Prepare to be suspended - LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume"); - LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd"); - - // At this point resuming the function will continue from resume_bb. - // This code is as if it is running inside the suspend block. - - // supply the awaiter return pointer - if (type_has_bits(g, result_type)) { - LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_ret_start + 1, ""); - if (result_loc == nullptr) { - // no copy needed - LLVMBuildStore(g->builder, LLVMConstNull(ZigLLVMGetGEPResultElementType(awaiter_ret_ptr_ptr)), - awaiter_ret_ptr_ptr); - } else { - LLVMBuildStore(g->builder, result_loc, awaiter_ret_ptr_ptr); - } - } - - // supply the error return trace pointer - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - bool is_llvm_alloca; - LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - assert(my_err_ret_trace_val != nullptr); - LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_index_trace_arg(g, result_type) + 1, ""); - LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); - } - - // caller's own frame pointer - LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_awaiter_index, ""); - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val, - LLVMAtomicOrderingRelease); - - LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait"); - LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend"); - LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); - - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2); - - LLVMAddCase(switch_instr, zero, complete_suspend_block); - LLVMAddCase(switch_instr, all_ones, early_return_block); - - // We discovered that another awaiter was already here. - LLVMPositionBuilderAtEnd(g->builder, bad_await_block); - gen_assertion(g, PanicMsgIdBadAwait, &instruction->base); - - // Rely on the target to resume us from suspension. - LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block); - LLVMBuildRetVoid(g->builder); - - // Early return: The async function has already completed. We must copy the result and - // the error return trace if applicable. - LLVMPositionBuilderAtEnd(g->builder, early_return_block); - gen_await_early_return(g, &instruction->base, target_frame_llvm_ty, target_frame_ptr, - result_type, ptr_result_type, result_loc, false); - LLVMBuildBr(g->builder, end_bb); - - LLVMPositionBuilderAtEnd(g->builder, resume_bb); - gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); - LLVMBuildBr(g->builder, end_bb); - - LLVMPositionBuilderAtEnd(g->builder, end_bb); - // Rely on the spill for the llvm_value to be populated. - // See the implementation of ir_llvm_value. - return nullptr; -} - -static LLVMValueRef ir_render_resume(CodeGen *g, Stage1Air *executable, Stage1AirInstResume *instruction) { - LLVMValueRef frame = ir_llvm_value(g, instruction->frame); - ZigType *frame_type = instruction->frame->value->type; - assert(frame_type->id == ZigTypeIdAnyFrame); - - gen_resume(g, g->anyframe_fn_type, nullptr, frame, ResumeIdManual); - return nullptr; -} - -static LLVMValueRef ir_render_frame_size(CodeGen *g, Stage1Air *executable, - Stage1AirInstFrameSize *instruction) -{ - LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn); - return gen_frame_size(g, fn_val); -} - -static LLVMValueRef ir_render_spill_begin(CodeGen *g, Stage1Air *executable, - Stage1AirInstSpillBegin *instruction) -{ - if (!fn_is_async(g->cur_fn)) - return nullptr; - - switch (instruction->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: { - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill); - LLVMBuildStore(g->builder, operand, ptr); - return nullptr; - } - - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_spill_end(CodeGen *g, Stage1Air *executable, Stage1AirInstSpillEnd *instruction) { - if (!fn_is_async(g->cur_fn)) - return ir_llvm_value(g, instruction->begin->operand); - - switch (instruction->begin->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: { - LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill); - LLVMTypeRef llvm_ty = g->builtin_types.entry_global_error_set->llvm_type; - return LLVMBuildLoad2(g->builder, llvm_ty, ptr, ""); - } - - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_vector_extract_elem(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorExtractElem *instruction) -{ - LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - LLVMValueRef index = ir_llvm_value(g, instruction->index); - return LLVMBuildExtractElement(g->builder, vector, index, ""); -} - -static void set_debug_location(CodeGen *g, Stage1AirInst *instruction) { - AstNode *source_node = instruction->source_node; - Scope *scope = instruction->scope; - - assert(source_node); - assert(scope); - - ZigLLVMSetCurrentDebugLocation(g->builder, node_line_onebased(source_node), - node_column_onebased(source_node), get_di_scope(g, scope)); -} - -static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Stage1AirInst *instruction) { - switch (instruction->id) { - case Stage1AirInstIdInvalid: - case Stage1AirInstIdConst: - case Stage1AirInstIdAlloca: - zig_unreachable(); - - case Stage1AirInstIdDeclVar: - return ir_render_decl_var(g, executable, (Stage1AirInstDeclVar *)instruction); - case Stage1AirInstIdReturn: - return ir_render_return(g, executable, (Stage1AirInstReturn *)instruction); - case Stage1AirInstIdBinOp: - return ir_render_bin_op(g, executable, (Stage1AirInstBinOp *)instruction); - case Stage1AirInstIdCast: - return ir_render_cast(g, executable, (Stage1AirInstCast *)instruction); - case Stage1AirInstIdUnreachable: - return ir_render_unreachable(g, executable, (Stage1AirInstUnreachable *)instruction); - case Stage1AirInstIdCondBr: - return ir_render_cond_br(g, executable, (Stage1AirInstCondBr *)instruction); - case Stage1AirInstIdBr: - return ir_render_br(g, executable, (Stage1AirInstBr *)instruction); - case Stage1AirInstIdBinaryNot: - return ir_render_binary_not(g, executable, (Stage1AirInstBinaryNot *)instruction); - case Stage1AirInstIdNegation: - return ir_render_negation(g, executable, (Stage1AirInstNegation *)instruction); - case Stage1AirInstIdLoadPtr: - return ir_render_load_ptr(g, executable, (Stage1AirInstLoadPtr *)instruction); - case Stage1AirInstIdStorePtr: - return ir_render_store_ptr(g, executable, (Stage1AirInstStorePtr *)instruction); - case Stage1AirInstIdVectorStoreElem: - return ir_render_vector_store_elem(g, executable, (Stage1AirInstVectorStoreElem *)instruction); - case Stage1AirInstIdVarPtr: - return ir_render_var_ptr(g, executable, (Stage1AirInstVarPtr *)instruction); - case Stage1AirInstIdReturnPtr: - return ir_render_return_ptr(g, executable, (Stage1AirInstReturnPtr *)instruction); - case Stage1AirInstIdElemPtr: - return ir_render_elem_ptr(g, executable, (Stage1AirInstElemPtr *)instruction); - case Stage1AirInstIdCall: - return ir_render_call(g, executable, (Stage1AirInstCall *)instruction); - case Stage1AirInstIdStructFieldPtr: - return ir_render_struct_field_ptr(g, executable, (Stage1AirInstStructFieldPtr *)instruction); - case Stage1AirInstIdUnionFieldPtr: - return ir_render_union_field_ptr(g, executable, (Stage1AirInstUnionFieldPtr *)instruction); - case Stage1AirInstIdAsm: - return ir_render_asm_gen(g, executable, (Stage1AirInstAsm *)instruction); - case Stage1AirInstIdTestNonNull: - return ir_render_test_non_null(g, executable, (Stage1AirInstTestNonNull *)instruction); - case Stage1AirInstIdOptionalUnwrapPtr: - return ir_render_optional_unwrap_ptr(g, executable, (Stage1AirInstOptionalUnwrapPtr *)instruction); - case Stage1AirInstIdClz: - return ir_render_clz(g, executable, (Stage1AirInstClz *)instruction); - case Stage1AirInstIdCtz: - return ir_render_ctz(g, executable, (Stage1AirInstCtz *)instruction); - case Stage1AirInstIdPopCount: - return ir_render_pop_count(g, executable, (Stage1AirInstPopCount *)instruction); - case Stage1AirInstIdSwitchBr: - return ir_render_switch_br(g, executable, (Stage1AirInstSwitchBr *)instruction); - case Stage1AirInstIdBswap: - return ir_render_bswap(g, executable, (Stage1AirInstBswap *)instruction); - case Stage1AirInstIdBitReverse: - return ir_render_bit_reverse(g, executable, (Stage1AirInstBitReverse *)instruction); - case Stage1AirInstIdPhi: - return ir_render_phi(g, executable, (Stage1AirInstPhi *)instruction); - case Stage1AirInstIdRef: - return ir_render_ref(g, executable, (Stage1AirInstRef *)instruction); - case Stage1AirInstIdErrName: - return ir_render_err_name(g, executable, (Stage1AirInstErrName *)instruction); - case Stage1AirInstIdCmpxchg: - return ir_render_cmpxchg(g, executable, (Stage1AirInstCmpxchg *)instruction); - case Stage1AirInstIdFence: - return ir_render_fence(g, executable, (Stage1AirInstFence *)instruction); - case Stage1AirInstIdReduce: - return ir_render_reduce(g, executable, (Stage1AirInstReduce *)instruction); - case Stage1AirInstIdTruncate: - return ir_render_truncate(g, executable, (Stage1AirInstTruncate *)instruction); - case Stage1AirInstIdBoolNot: - return ir_render_bool_not(g, executable, (Stage1AirInstBoolNot *)instruction); - case Stage1AirInstIdMemset: - return ir_render_memset(g, executable, (Stage1AirInstMemset *)instruction); - case Stage1AirInstIdMemcpy: - return ir_render_memcpy(g, executable, (Stage1AirInstMemcpy *)instruction); - case Stage1AirInstIdSlice: - return ir_render_slice(g, executable, (Stage1AirInstSlice *)instruction); - case Stage1AirInstIdBreakpoint: - return ir_render_breakpoint(g, executable, (Stage1AirInstBreakpoint *)instruction); - case Stage1AirInstIdReturnAddress: - return ir_render_return_address(g, executable, (Stage1AirInstReturnAddress *)instruction); - case Stage1AirInstIdFrameAddress: - return ir_render_frame_address(g, executable, (Stage1AirInstFrameAddress *)instruction); - case Stage1AirInstIdFrameHandle: - return ir_render_handle(g, executable, (Stage1AirInstFrameHandle *)instruction); - case Stage1AirInstIdOverflowOp: - return ir_render_overflow_op(g, executable, (Stage1AirInstOverflowOp *)instruction); - case Stage1AirInstIdTestErr: - return ir_render_test_err(g, executable, (Stage1AirInstTestErr *)instruction); - case Stage1AirInstIdUnwrapErrCode: - return ir_render_unwrap_err_code(g, executable, (Stage1AirInstUnwrapErrCode *)instruction); - case Stage1AirInstIdUnwrapErrPayload: - return ir_render_unwrap_err_payload(g, executable, (Stage1AirInstUnwrapErrPayload *)instruction); - case Stage1AirInstIdOptionalWrap: - return ir_render_optional_wrap(g, executable, (Stage1AirInstOptionalWrap *)instruction); - case Stage1AirInstIdErrWrapCode: - return ir_render_err_wrap_code(g, executable, (Stage1AirInstErrWrapCode *)instruction); - case Stage1AirInstIdErrWrapPayload: - return ir_render_err_wrap_payload(g, executable, (Stage1AirInstErrWrapPayload *)instruction); - case Stage1AirInstIdUnionTag: - return ir_render_union_tag(g, executable, (Stage1AirInstUnionTag *)instruction); - case Stage1AirInstIdPtrCast: - return ir_render_ptr_cast(g, executable, (Stage1AirInstPtrCast *)instruction); - case Stage1AirInstIdBitCast: - return ir_render_bit_cast(g, executable, (Stage1AirInstBitCast *)instruction); - case Stage1AirInstIdWidenOrShorten: - return ir_render_widen_or_shorten(g, executable, (Stage1AirInstWidenOrShorten *)instruction); - case Stage1AirInstIdPtrToInt: - return ir_render_ptr_to_int(g, executable, (Stage1AirInstPtrToInt *)instruction); - case Stage1AirInstIdIntToPtr: - return ir_render_int_to_ptr(g, executable, (Stage1AirInstIntToPtr *)instruction); - case Stage1AirInstIdIntToEnum: - return ir_render_int_to_enum(g, executable, (Stage1AirInstIntToEnum *)instruction); - case Stage1AirInstIdIntToErr: - return ir_render_int_to_err(g, executable, (Stage1AirInstIntToErr *)instruction); - case Stage1AirInstIdErrToInt: - return ir_render_err_to_int(g, executable, (Stage1AirInstErrToInt *)instruction); - case Stage1AirInstIdPanic: - return ir_render_panic(g, executable, (Stage1AirInstPanic *)instruction); - case Stage1AirInstIdTagName: - return ir_render_enum_tag_name(g, executable, (Stage1AirInstTagName *)instruction); - case Stage1AirInstIdFieldParentPtr: - return ir_render_field_parent_ptr(g, executable, (Stage1AirInstFieldParentPtr *)instruction); - case Stage1AirInstIdAlignCast: - return ir_render_align_cast(g, executable, (Stage1AirInstAlignCast *)instruction); - case Stage1AirInstIdErrorReturnTrace: - return ir_render_error_return_trace(g, executable, (Stage1AirInstErrorReturnTrace *)instruction); - case Stage1AirInstIdAtomicRmw: - return ir_render_atomic_rmw(g, executable, (Stage1AirInstAtomicRmw *)instruction); - case Stage1AirInstIdAtomicLoad: - return ir_render_atomic_load(g, executable, (Stage1AirInstAtomicLoad *)instruction); - case Stage1AirInstIdAtomicStore: - return ir_render_atomic_store(g, executable, (Stage1AirInstAtomicStore *)instruction); - case Stage1AirInstIdSaveErrRetAddr: - return ir_render_save_err_ret_addr(g, executable, (Stage1AirInstSaveErrRetAddr *)instruction); - case Stage1AirInstIdFloatOp: - return ir_render_float_op(g, executable, (Stage1AirInstFloatOp *)instruction); - case Stage1AirInstIdMulAdd: - return ir_render_mul_add(g, executable, (Stage1AirInstMulAdd *)instruction); - case Stage1AirInstIdArrayToVector: - return ir_render_array_to_vector(g, executable, (Stage1AirInstArrayToVector *)instruction); - case Stage1AirInstIdVectorToArray: - return ir_render_vector_to_array(g, executable, (Stage1AirInstVectorToArray *)instruction); - case Stage1AirInstIdAssertZero: - return ir_render_assert_zero(g, executable, (Stage1AirInstAssertZero *)instruction); - case Stage1AirInstIdAssertNonNull: - return ir_render_assert_non_null(g, executable, (Stage1AirInstAssertNonNull *)instruction); - case Stage1AirInstIdPtrOfArrayToSlice: - return ir_render_ptr_of_array_to_slice(g, executable, (Stage1AirInstPtrOfArrayToSlice *)instruction); - case Stage1AirInstIdSuspendBegin: - return ir_render_suspend_begin(g, executable, (Stage1AirInstSuspendBegin *)instruction); - case Stage1AirInstIdSuspendFinish: - return ir_render_suspend_finish(g, executable, (Stage1AirInstSuspendFinish *)instruction); - case Stage1AirInstIdResume: - return ir_render_resume(g, executable, (Stage1AirInstResume *)instruction); - case Stage1AirInstIdFrameSize: - return ir_render_frame_size(g, executable, (Stage1AirInstFrameSize *)instruction); - case Stage1AirInstIdAwait: - return ir_render_await(g, executable, (Stage1AirInstAwait *)instruction); - case Stage1AirInstIdSpillBegin: - return ir_render_spill_begin(g, executable, (Stage1AirInstSpillBegin *)instruction); - case Stage1AirInstIdSpillEnd: - return ir_render_spill_end(g, executable, (Stage1AirInstSpillEnd *)instruction); - case Stage1AirInstIdShuffleVector: - return ir_render_shuffle_vector(g, executable, (Stage1AirInstShuffleVector *) instruction); - case Stage1AirInstIdSelect: - return ir_render_select(g, executable, (Stage1AirInstSelect *) instruction); - case Stage1AirInstIdSplat: - return ir_render_splat(g, executable, (Stage1AirInstSplat *) instruction); - case Stage1AirInstIdVectorExtractElem: - return ir_render_vector_extract_elem(g, executable, (Stage1AirInstVectorExtractElem *) instruction); - case Stage1AirInstIdWasmMemorySize: - return ir_render_wasm_memory_size(g, executable, (Stage1AirInstWasmMemorySize *) instruction); - case Stage1AirInstIdWasmMemoryGrow: - return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction); - case Stage1AirInstIdExtern: - return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction); - case Stage1AirInstIdPrefetch: - return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction); - } - zig_unreachable(); -} - -static void ir_render(CodeGen *g, ZigFn *fn_entry) { - assert(fn_entry); - - Stage1Air *executable = &fn_entry->analyzed_executable; - assert(executable->basic_block_list.length > 0); - - for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *current_block = executable->basic_block_list.at(block_i); - if (get_scope_typeof(current_block->scope) != nullptr) { - LLVMBuildBr(g->builder, current_block->llvm_block); - } - assert(current_block->llvm_block); - LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = current_block->instruction_list.at(instr_i); - if (instruction->ref_count == 0 && !ir_inst_gen_has_side_effects(instruction)) - continue; - if (get_scope_typeof(instruction->scope) != nullptr) - continue; - - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - instruction->llvm_value = ir_render_instruction(g, executable, instruction); - if (instruction->spill != nullptr && instruction->llvm_value != nullptr) { - LLVMValueRef spill_ptr = ir_llvm_value(g, instruction->spill); - gen_assign_raw(g, spill_ptr, instruction->spill->value->type, instruction->llvm_value); - instruction->llvm_value = nullptr; - } - } - current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); - } -} - -static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_const_val, size_t field_index); -static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_const_val, size_t index); -static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ZigValue *union_const_val); -static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val); -static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ZigValue *err_union_const_val); -static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ZigValue *optional_const_val); - -static LLVMValueRef gen_parent_ptr(CodeGen *g, ZigValue *val, ConstParent *parent) { - switch (parent->id) { - case ConstParentIdNone: - render_const_val(g, val, ""); - render_const_val_global(g, val, ""); - return val->llvm_global; - case ConstParentIdStruct: { - ZigValue *struct_val = parent->data.p_struct.struct_val; - size_t src_field_index = parent->data.p_struct.field_index; - size_t gen_field_index = struct_val->type->data.structure.fields[src_field_index]->gen_index; - return gen_const_ptr_struct_recursive(g, struct_val, gen_field_index); - } - case ConstParentIdErrUnionCode: - return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val); - case ConstParentIdErrUnionPayload: - return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val); - case ConstParentIdOptionalPayload: - return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val); - case ConstParentIdArray: - return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, - parent->data.p_array.elem_index); - case ConstParentIdUnion: - return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val); - case ConstParentIdScalar: - render_const_val(g, parent->data.p_scalar.scalar_val, ""); - render_const_val_global(g, parent->data.p_scalar.scalar_val, ""); - return parent->data.p_scalar.scalar_val->llvm_global; - } - zig_unreachable(); -} - -static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_const_val, size_t index) { - expand_undef_array(g, array_const_val); - ConstParent *parent = &array_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); - - ZigType *usize = g->builtin_types.entry_usize; - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_const_val->type); - LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr, LLVMPointerType(array_llvm_ty, 0)); - LLVMValueRef indices[] = { - LLVMConstNull(usize->llvm_type), - LLVMConstInt(usize->llvm_type, index, false), - }; - return LLVMConstInBoundsGEP2(array_llvm_ty, casted_base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_const_val, size_t field_index) { - ConstParent *parent = &struct_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); - - LLVMValueRef indices[] = { - LLVMConstNull(LLVMInt32Type()), - LLVMConstInt(LLVMInt32Type(), field_index, false), - }; - - // The structure pointed by base_ptr may include trailing padding for - // alignment purposes and have the following LLVM type: <{ %T, [N x i8] }>. - // Add an extra bitcast as we're only interested in the %T part. - assert(handle_is_ptr(g, struct_const_val->type)); - - LLVMTypeRef struct_llvm_ty = get_llvm_type(g, struct_const_val->type); - LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr, LLVMPointerType(struct_llvm_ty, 0)); - return LLVMConstInBoundsGEP2(struct_llvm_ty, casted_base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val) { - ConstParent *parent = &err_union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), err_union_err_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, err_union_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ZigValue *err_union_const_val) { - ConstParent *parent = &err_union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), err_union_payload_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, err_union_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ZigValue *optional_const_val) { - ConstParent *parent = &optional_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), maybe_child_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, optional_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ZigValue *union_const_val) { - ConstParent *parent = &union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); - - // Slot in the structure where the payload is stored, if equal to SIZE_MAX - // the union has no tag and a single field and is collapsed into the field - // itself - size_t union_payload_index = union_const_val->type->data.unionation.gen_union_index; - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), union_payload_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, union_const_val->type), base_ptr, indices, (union_payload_index != SIZE_MAX) ? 2 : 1); -} - -static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ZigValue *const_val) { - switch (const_val->special) { - case ConstValSpecialLazy: - case ConstValSpecialRuntime: - zig_unreachable(); - case ConstValSpecialUndef: - return LLVMConstInt(big_int_type_ref, 0, false); - case ConstValSpecialStatic: - break; - } - - ZigType *type_entry = const_val->type; - assert(type_has_bits(g, type_entry)); - switch (type_entry->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdBool: - return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false); - case ZigTypeIdEnum: - { - assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr); - LLVMValueRef int_val = gen_const_val(g, const_val, ""); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdInt: - { - LLVMValueRef int_val = gen_const_val(g, const_val, ""); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdFloat: - { - LLVMValueRef float_val = gen_const_val(g, const_val, ""); - LLVMValueRef int_val = LLVMConstFPToUI(float_val, - LLVMIntType((unsigned)type_entry->data.floating.bit_count)); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdOptional: - { - LLVMValueRef ptr_val = gen_const_val(g, const_val, ""); - LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type); - return LLVMConstZExt(ptr_size_int_val, big_int_type_ref); - } - case ZigTypeIdArray: { - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - if (const_val->data.x_array.special == ConstArraySpecialUndef) { - return val; - } - expand_undef_array(g, const_val); - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - uint32_t packed_bits_size = type_size_bits(g, type_entry->data.array.child_type); - size_t used_bits = 0; - for (size_t i = 0; i < type_entry->data.array.len; i += 1) { - ZigValue *elem_val = &const_val->data.x_array.data.s_none.elements[i]; - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); - - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - - if (type_entry->data.array.sentinel != nullptr) { - ZigValue *elem_val = type_entry->data.array.sentinel; - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); - - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - return val; - } - case ZigTypeIdVector: - zig_panic("TODO bit pack a vector"); - case ZigTypeIdUnion: - zig_panic("TODO bit pack a union"); - case ZigTypeIdStruct: - { - assert(type_entry->data.structure.layout == ContainerLayoutPacked); - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - size_t used_bits = 0; - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX || field->is_comptime) { - continue; - } - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, const_val->data.x_struct.fields[i]); - uint32_t packed_bits_size = type_size_bits(g, field->type_entry); - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - return val; - } - case ZigTypeIdFnFrame: - zig_panic("TODO bit pack an async function frame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO bit pack an anyframe"); - } - zig_unreachable(); -} - -// We have this because union constants can't be represented by the official union type, -// and this property bubbles up in whatever aggregate type contains a union constant -static bool is_llvm_value_unnamed_type(CodeGen *g, ZigType *type_entry, LLVMValueRef val) { - return LLVMTypeOf(val) != get_llvm_type(g, type_entry); -} - -static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const char *name) { - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - { - ZigValue *pointee = const_val->data.x_ptr.data.ref.pointee; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - { - ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; - assert(array_const_val->type->id == ZigTypeIdArray); - if (!type_has_bits(g, array_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseStruct: - { - ZigValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; - assert(struct_const_val->type->id == ZigTypeIdStruct); - if (!type_has_bits(g, struct_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; - size_t gen_field_index = struct_const_val->type->data.structure.fields[src_field_index]->gen_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, - gen_field_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseErrorUnionCode: - { - ZigValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; - assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); - if (!type_has_bits(g, err_union_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseErrorUnionPayload: - { - ZigValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; - assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); - if (!type_has_bits(g, err_union_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseOptionalPayload: - { - ZigValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; - assert(optional_const_val->type->id == ZigTypeIdOptional); - if (!type_has_bits(g, optional_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialHardCodedAddr: - { - uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr( - LLVMConstInt(usize->llvm_type, addr_value, false), get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - case ConstPtrSpecialFunction: - return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), - get_llvm_type(g, const_val->type)); - case ConstPtrSpecialNull: - return LLVMConstNull(get_llvm_type(g, const_val->type)); - } - zig_unreachable(); -} - -static LLVMValueRef gen_const_val_err_set(CodeGen *g, ZigValue *const_val, const char *name) { - uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value; - return LLVMConstInt(get_llvm_type(g, g->builtin_types.entry_global_error_set), value, false); -} - -static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name) { - Error err; - - ZigType *type_entry = const_val->type; - assert(type_has_bits(g, type_entry)); - - if (const_val->special == ConstValSpecialLazy && - (err = ir_resolve_lazy(g, nullptr, const_val))) - codegen_report_errors_and_exit(g); - - switch (const_val->special) { - case ConstValSpecialLazy: - case ConstValSpecialRuntime: - zig_unreachable(); - case ConstValSpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstValSpecialStatic: - break; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull))) - zig_unreachable(); - - switch (type_entry->id) { - case ZigTypeIdInt: - return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint); - case ZigTypeIdErrorSet: - return gen_const_val_err_set(g, const_val, name); - case ZigTypeIdFloat: - switch (type_entry->data.floating.bit_count) { - case 16: - { - LLVMValueRef as_int = LLVMConstInt(LLVMInt16Type(), const_val->data.x_f16.v, false); - return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); - } - case 32: - return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32); - case 64: - return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f64); - case 80: { - LLVMTypeRef llvm_i80 = LLVMIntType(80); - LLVMValueRef x = LLVMConstInt(llvm_i80, const_val->data.x_f80.signExp, false); - x = LLVMConstShl(x, LLVMConstInt(llvm_i80, 64, false)); - x = LLVMConstOr(x, LLVMConstInt(llvm_i80, const_val->data.x_f80.signif, false)); - if (target_has_f80(g->zig_target)) { - return LLVMConstBitCast(x, LLVMX86FP80Type()); - } else { - return x; - } - } - case 128: - { - uint64_t buf[2]; - - // LLVM seems to require that the lower half of the f128 be - // placed first in the buffer. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - buf[0] = const_val->data.x_f128.v[0]; - buf[1] = const_val->data.x_f128.v[1]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - buf[0] = const_val->data.x_f128.v[1]; - buf[1] = const_val->data.x_f128.v[0]; -#else -#error Unsupported endian -#endif - - LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf); - return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); - } - default: - zig_unreachable(); - } - case ZigTypeIdBool: - if (const_val->data.x_bool) { - return LLVMConstAllOnes(LLVMInt1Type()); - } else { - return LLVMConstNull(LLVMInt1Type()); - } - case ZigTypeIdOptional: - { - ZigType *child_type = type_entry->data.maybe.child_type; - - if (get_src_ptr_type(type_entry) != nullptr) { - bool has_bits; - if ((err = type_has_bits2(g, child_type, &has_bits))) - codegen_report_errors_and_exit(g); - - if (has_bits) - return gen_const_val_ptr(g, const_val, name); - - // No bits, treat this value as a boolean - const unsigned bool_val = optional_value_is_null(const_val) ? 0 : 1; - return LLVMConstInt(LLVMInt1Type(), bool_val, false); - } else if (child_type->id == ZigTypeIdErrorSet) { - return gen_const_val_err_set(g, const_val, name); - } else if (!type_has_bits(g, child_type)) { - return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); - } else { - LLVMValueRef child_val; - LLVMValueRef maybe_val; - bool make_unnamed_struct; - if (const_val->data.x_optional) { - child_val = gen_const_val(g, const_val->data.x_optional, ""); - maybe_val = LLVMConstAllOnes(LLVMInt1Type()); - - make_unnamed_struct = is_llvm_value_unnamed_type(g, const_val->type, child_val); - } else { - child_val = LLVMGetUndef(get_llvm_type(g, child_type)); - maybe_val = LLVMConstNull(LLVMInt1Type()); - - make_unnamed_struct = false; - } - - LLVMValueRef fields[] = { - child_val, - maybe_val, - nullptr, - }; - if (make_unnamed_struct) { - LLVMValueRef result = LLVMConstStruct(fields, 2, false); - uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1); - uint64_t end_offset = last_field_offset + - LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1])); - uint64_t expected_sz = LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, type_entry)); - unsigned pad_sz = expected_sz - end_offset; - if (pad_sz != 0) { - fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); - result = LLVMConstStruct(fields, 3, false); - } - uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - assert(actual_sz == expected_sz); - return result; - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2); - } - } - } - case ZigTypeIdStruct: - { - LLVMValueRef *fields = heap::c_allocator.allocate(type_entry->data.structure.gen_field_count); - size_t src_field_count = type_entry->data.structure.src_field_count; - bool make_unnamed_struct = false; - assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull); - if (type_entry->data.structure.layout == ContainerLayoutPacked) { - size_t src_field_index = 0; - while (src_field_index < src_field_count) { - TypeStructField *type_struct_field = type_entry->data.structure.fields[src_field_index]; - if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { - src_field_index += 1; - continue; - } - - size_t src_field_index_end = src_field_index + 1; - for (; src_field_index_end < src_field_count; src_field_index_end += 1) { - TypeStructField *it_field = type_entry->data.structure.fields[src_field_index_end]; - if (it_field->gen_index != type_struct_field->gen_index) - break; - } - - if (src_field_index + 1 == src_field_index_end && !type_entry->data.structure.misaligned_field) { - ZigValue *field_val = const_val->data.x_struct.fields[src_field_index]; - LLVMValueRef val = gen_const_val(g, field_val, ""); - fields[type_struct_field->gen_index] = val; - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val); - } else { - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry), - (unsigned)type_struct_field->gen_index); - const size_t size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, field_ty); - const size_t size_in_bits = size_in_bytes * 8; - LLVMTypeRef big_int_type_ref = LLVMIntType(size_in_bits); - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - size_t used_bits = 0; - for (size_t i = src_field_index; i < src_field_index_end; i += 1) { - TypeStructField *it_field = type_entry->data.structure.fields[i]; - if (it_field->gen_index == SIZE_MAX) { - continue; - } - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, - const_val->data.x_struct.fields[i]); - uint32_t packed_bits_size = type_size_bits(g, it_field->type_entry); - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, - size_in_bits - used_bits - packed_bits_size, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - } - used_bits += packed_bits_size; - } - assert(size_in_bits >= used_bits); - if (LLVMGetTypeKind(field_ty) != LLVMArrayTypeKind) { - assert(LLVMGetTypeKind(field_ty) == LLVMIntegerTypeKind); - fields[type_struct_field->gen_index] = val; - } else { - const LLVMValueRef AMT = LLVMConstInt(LLVMTypeOf(val), 8, false); - - LLVMValueRef *values = heap::c_allocator.allocate(size_in_bytes); - for (size_t i = 0; i < size_in_bytes; i++) { - const size_t idx = is_big_endian ? size_in_bytes - 1 - i : i; - values[idx] = LLVMConstTruncOrBitCast(val, LLVMInt8Type()); - val = LLVMConstLShr(val, AMT); - } - - fields[type_struct_field->gen_index] = LLVMConstArray(LLVMInt8Type(), values, size_in_bytes); - } - } - - src_field_index = src_field_index_end; - } - } else { - for (uint32_t i = 0; i < src_field_count; i += 1) { - TypeStructField *type_struct_field = type_entry->data.structure.fields[i]; - if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { - continue; - } - ZigValue *field_val = const_val->data.x_struct.fields[i]; - if (field_val == nullptr) { - add_node_error(g, type_struct_field->decl_node, - buf_sprintf("compiler bug: generating const value for struct field '%s'", - buf_ptr(type_struct_field->name))); - codegen_report_errors_and_exit(g); - } - ZigType *field_type = field_val->type; - assert(field_type != nullptr); - if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) { - zig_unreachable(); - } - - LLVMValueRef val = gen_const_val(g, field_val, ""); - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_type, val); - - // Find the next runtime field - size_t next_rt_gen_index = type_entry->data.structure.gen_field_count; - size_t next_offset = type_entry->abi_size; - for (size_t j = i + 1; j < src_field_count; j++) { - const size_t index = type_entry->data.structure.fields[j]->gen_index; - const size_t offset = type_entry->data.structure.fields[j]->offset; - - if (index != SIZE_MAX) { - next_rt_gen_index = index; - next_offset = offset; - break; - } - } - - // How much padding is needed to reach the next field - const size_t pad_bytes = next_offset - - (type_struct_field->offset + LLVMABISizeOfType(g->target_data_ref, LLVMTypeOf(val))); - // Catch underflow - assert((ssize_t)pad_bytes >= 0); - - if (type_struct_field->gen_index + 1 != next_rt_gen_index) { - // If there's a hole between this field and the next - // we have an alignment gap to fill - fields[type_struct_field->gen_index] = val; - fields[type_struct_field->gen_index + 1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)); - } else if (pad_bytes != 0) { - LLVMValueRef padded_val[] = { - val, - LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)), - }; - fields[type_struct_field->gen_index] = LLVMConstStruct(padded_val, 2, true); - make_unnamed_struct = true; - } else { - fields[type_struct_field->gen_index] = val; - } - } - } - if (make_unnamed_struct) { - LLVMValueRef unnamed_struct = LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, - type_entry->data.structure.layout == ContainerLayoutPacked); - heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count); - return unnamed_struct; - } else { - LLVMValueRef named_struct = LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, type_entry->data.structure.gen_field_count); - heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count); - return named_struct; - } - } - case ZigTypeIdArray: - { - uint64_t len = type_entry->data.array.len; - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstArraySpecialNone: { - uint64_t extra_len_from_sentinel = (type_entry->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = len + extra_len_from_sentinel; - LLVMValueRef *values = heap::c_allocator.allocate(full_len); - LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type); - bool make_unnamed_struct = false; - for (uint64_t i = 0; i < len; i += 1) { - ZigValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; - LLVMValueRef val = gen_const_val(g, elem_value, ""); - values[i] = val; - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val); - } - if (type_entry->data.array.sentinel != nullptr) { - values[len] = gen_const_val(g, type_entry->data.array.sentinel, ""); - } - if (make_unnamed_struct) { - LLVMValueRef unnamed_struct = LLVMConstStruct(values, full_len, true); - heap::c_allocator.deallocate(values, full_len); - return unnamed_struct; - } else { - LLVMValueRef array = LLVMConstArray(element_type_ref, values, (unsigned)full_len); - heap::c_allocator.deallocate(values, full_len); - return array; - } - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), - type_entry->data.array.sentinel == nullptr); - } - } - zig_unreachable(); - } - case ZigTypeIdVector: { - uint32_t len = type_entry->data.vector.len; - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstArraySpecialNone: { - LLVMValueRef *values = heap::c_allocator.allocate(len); - for (uint64_t i = 0; i < len; i += 1) { - ZigValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; - values[i] = gen_const_val(g, elem_value, ""); - } - LLVMValueRef vector = LLVMConstVector(values, len); - heap::c_allocator.deallocate(values, len); - return vector; - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - assert(buf_len(buf) == len); - LLVMValueRef *values = heap::c_allocator.allocate(len); - for (uint64_t i = 0; i < len; i += 1) { - values[i] = LLVMConstInt(g->builtin_types.entry_u8->llvm_type, buf_ptr(buf)[i], false); - } - LLVMValueRef vector = LLVMConstVector(values, len); - heap::c_allocator.deallocate(values, len); - return vector; - } - } - zig_unreachable(); - } - case ZigTypeIdUnion: - { - // Force type_entry->data.unionation.union_llvm_type to get resolved - (void)get_llvm_type(g, type_entry); - - if (type_entry->data.unionation.gen_field_count == 0) { - if (type_entry->data.unionation.tag_type == nullptr) { - return nullptr; - } else { - return bigint_to_llvm_const(get_llvm_type(g, type_entry->data.unionation.tag_type), - &const_val->data.x_union.tag); - } - } - - LLVMTypeRef union_type_ref = type_entry->data.unionation.union_llvm_type; - assert(union_type_ref != nullptr); - - LLVMValueRef union_value_ref; - bool make_unnamed_struct; - ZigValue *payload_value = const_val->data.x_union.payload; - if (payload_value == nullptr || !type_has_bits(g, payload_value->type)) { - if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) - return LLVMGetUndef(get_llvm_type(g, type_entry)); - - union_value_ref = LLVMGetUndef(union_type_ref); - make_unnamed_struct = false; - } else { - uint64_t field_type_bytes = LLVMABISizeOfType(g->target_data_ref, - get_llvm_type(g, payload_value->type)); - uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; - LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); - make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) || - payload_value->type != type_entry->data.unionation.most_aligned_union_member->type_entry; - - { - if (pad_bytes == 0) { - union_value_ref = correctly_typed_value; - } else { - LLVMValueRef fields[2]; - fields[0] = correctly_typed_value; - fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); - if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { - union_value_ref = LLVMConstStruct(fields, 2, false); - } else { - union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); - } - } - } - - if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { - return union_value_ref; - } - } - - LLVMValueRef tag_value = bigint_to_llvm_const( - get_llvm_type(g, type_entry->data.unionation.tag_type), - &const_val->data.x_union.tag); - - LLVMValueRef fields[3]; - fields[type_entry->data.unionation.gen_union_index] = union_value_ref; - fields[type_entry->data.unionation.gen_tag_index] = tag_value; - - if (make_unnamed_struct) { - LLVMValueRef result = LLVMConstStruct(fields, 2, false); - uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1); - uint64_t end_offset = last_field_offset + - LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1])); - uint64_t expected_sz = LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, type_entry)); - unsigned pad_sz = expected_sz - end_offset; - if (pad_sz != 0) { - fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); - result = LLVMConstStruct(fields, 3, false); - } - uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - assert(actual_sz == expected_sz); - return result; - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2); - } - - } - - case ZigTypeIdEnum: - return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_enum_tag); - case ZigTypeIdFn: - if (const_val->data.x_ptr.special == ConstPtrSpecialFunction && - const_val->data.x_ptr.mut != ConstPtrMutComptimeConst) { - zig_unreachable(); - } - // Treat it the same as we do for pointers - return gen_const_val_ptr(g, const_val, name); - case ZigTypeIdPointer: - return gen_const_val_ptr(g, const_val, name); - case ZigTypeIdErrorUnion: - { - ZigType *payload_type = type_entry->data.error_union.payload_type; - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - if (!type_has_bits(g, payload_type)) { - assert(type_has_bits(g, err_set_type)); - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - uint64_t value = (err_set == nullptr) ? 0 : err_set->value; - return LLVMConstInt(get_llvm_type(g, g->err_tag_type), value, false); - } else if (!type_has_bits(g, err_set_type)) { - assert(type_has_bits(g, payload_type)); - return gen_const_val(g, const_val->data.x_err_union.payload, ""); - } else { - LLVMValueRef err_tag_value; - LLVMValueRef err_payload_value; - bool make_unnamed_struct; - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - if (err_set != nullptr) { - err_tag_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type), err_set->value, false); - err_payload_value = LLVMConstNull(get_llvm_type(g, payload_type)); - make_unnamed_struct = false; - } else { - err_tag_value = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - ZigValue *payload_val = const_val->data.x_err_union.payload; - err_payload_value = gen_const_val(g, payload_val, ""); - make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value); - } - LLVMValueRef fields[3]; - fields[err_union_err_index] = err_tag_value; - fields[err_union_payload_index] = err_payload_value; - size_t field_count = 2; - if (type_entry->data.error_union.pad_llvm_type != nullptr) { - fields[2] = LLVMGetUndef(type_entry->data.error_union.pad_llvm_type); - field_count = 3; - } - if (make_unnamed_struct) { - return LLVMConstStruct(fields, field_count, false); - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count); - } - } - } - case ZigTypeIdVoid: - return nullptr; - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdFnFrame: - zig_panic("TODO: gen_const_val ZigTypeIdFnFrame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO: gen_const_val ZigTypeIdAnyFrame"); - } - zig_unreachable(); -} - -static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) { - if (!const_val->llvm_value) - const_val->llvm_value = gen_const_val(g, const_val, name); - - if (const_val->llvm_global) - LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); -} - -static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name) { - if (!const_val->llvm_global) { - LLVMTypeRef type_ref = const_val->llvm_value ? - LLVMTypeOf(const_val->llvm_value) : get_llvm_type(g, const_val->type); - LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, name); - LLVMSetLinkage(global_value, (name == nullptr) ? LLVMPrivateLinkage : LLVMInternalLinkage); - LLVMSetGlobalConstant(global_value, true); - LLVMSetUnnamedAddr(global_value, true); - LLVMSetAlignment(global_value, (const_val->llvm_align == 0) ? - get_abi_alignment(g, const_val->type) : const_val->llvm_align); - - const_val->llvm_global = global_value; - } - - if (const_val->llvm_value) - LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); -} - -static void generate_error_name_table(CodeGen *g) { - if (g->err_name_table != nullptr || !g->generate_error_name_table) { - return; - } - - assert(g->errors_by_index.length > 0); - - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - - LLVMValueRef *values = heap::c_allocator.allocate(g->errors_by_index.length); - values[0] = LLVMGetUndef(get_llvm_type(g, str_type)); - for (size_t i = 1; i < g->errors_by_index.length; i += 1) { - ErrorTableEntry *err_entry = g->errors_by_index.at(i); - Buf *name = &err_entry->name; - - g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); - - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), false); - LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); - LLVMSetInitializer(str_global, str_init); - LLVMSetLinkage(str_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(str_global, true); - LLVMSetUnnamedAddr(str_global, true); - LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); - - LLVMValueRef fields[] = { - LLVMConstBitCast(str_global, get_llvm_type(g, u8_ptr_type)), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false), - }; - values[i] = LLVMConstNamedStruct(get_llvm_type(g, str_type), fields, 2); - } - - LLVMValueRef err_name_table_init = LLVMConstArray(get_llvm_type(g, str_type), values, (unsigned)g->errors_by_index.length); - heap::c_allocator.deallocate(values, g->errors_by_index.length); - - g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), - get_mangled_name(g, buf_ptr(buf_create_from_str("__zig_err_name_table")))); - LLVMSetInitializer(g->err_name_table, err_name_table_init); - LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage); - LLVMSetGlobalConstant(g->err_name_table, true); - LLVMSetUnnamedAddr(g->err_name_table, true); - LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init))); -} - -static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) { - Stage1Air *executable = &fn->analyzed_executable; - assert(executable->basic_block_list.length > 0); - LLVMValueRef fn_val = fn_llvm_value(g, fn); - LLVMBasicBlockRef first_bb = nullptr; - if (fn_is_async(fn)) { - first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch"); - g->cur_preamble_llvm_block = first_bb; - } - for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *bb = executable->basic_block_list.at(block_i); - bb->llvm_block = LLVMAppendBasicBlock(fn_val, bb->name_hint); - } - if (first_bb == nullptr) { - first_bb = executable->basic_block_list.at(0)->llvm_block; - } - LLVMPositionBuilderAtEnd(g->builder, first_bb); -} - -static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, - ZigType *type_entry) -{ - if (g->strip_debug_symbols) { - return; - } - - assert(var->gen_is_const); - assert(type_entry); - - ZigType *import = get_scope_import(var->parent_scope); - assert(import); - - bool is_local_to_unit = true; - ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, type_entry), is_local_to_unit); - - // TODO ^^ make an actual global variable -} - -static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { - bool is_extern = var->decl_node->data.variable_declaration.is_extern; - bool is_export = var->decl_node->data.variable_declaration.is_export; - bool is_internal_linkage = !is_extern && !is_export; - if (var->is_thread_local && (!g->is_single_threaded || !is_internal_linkage)) { - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } -} - -static void do_code_gen(CodeGen *g) { - Error err; - assert(!g->errors.length); - - generate_error_name_table(g); - - // Generate module level variables - for (size_t i = 0; i < g->global_vars.length; i += 1) { - TldVar *tld_var = g->global_vars.at(i); - ZigVar *var = tld_var->var; - - if (var->var_type->id == ZigTypeIdComptimeFloat) { - // Generate debug info for it but that's it. - ZigValue *const_val = var->const_value; - assert(const_val->special != ConstValSpecialRuntime); - if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) - zig_unreachable(); - if (const_val->type != var->var_type) { - zig_panic("TODO debug info for var with ptr casted value"); - } - ZigType *var_type = g->builtin_types.entry_f128; - ZigValue coerced_value = {}; - coerced_value.special = ConstValSpecialStatic; - coerced_value.type = var_type; - coerced_value.data.x_f128 = bigfloat_to_f128(&const_val->data.x_bigfloat); - LLVMValueRef init_val = gen_const_val(g, &coerced_value, ""); - gen_global_var(g, var, init_val, var_type); - continue; - } - - if (var->var_type->id == ZigTypeIdComptimeInt) { - // Generate debug info for it but that's it. - ZigValue *const_val = var->const_value; - assert(const_val->special != ConstValSpecialRuntime); - if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) - zig_unreachable(); - if (const_val->type != var->var_type) { - zig_panic("TODO debug info for var with ptr casted value"); - } - size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); - if (bits_needed < 8) { - bits_needed = 8; - } - ZigType *var_type = get_int_type(g, const_val->data.x_bigint.is_negative, bits_needed); - LLVMValueRef init_val = bigint_to_llvm_const(get_llvm_type(g, var_type), &const_val->data.x_bigint); - gen_global_var(g, var, init_val, var_type); - continue; - } - - if (!type_has_bits(g, var->var_type)) - continue; - - assert(var->decl_node); - - GlobalLinkageId linkage; - const char *unmangled_name = var->name; - const char *symbol_name; - if (var->export_list.length == 0) { - if (var->decl_node->data.variable_declaration.is_extern) { - symbol_name = unmangled_name; - linkage = GlobalLinkageIdStrong; - } else { - symbol_name = get_mangled_name(g, unmangled_name); - linkage = GlobalLinkageIdInternal; - } - } else { - GlobalExport *global_export = &var->export_list.items[0]; - symbol_name = buf_ptr(&global_export->name); - linkage = global_export->linkage; - } - - LLVMValueRef global_value; - bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; - if (externally_initialized) { - LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); - if (existing_llvm_var) { - global_value = LLVMConstBitCast(existing_llvm_var, - LLVMPointerType(get_llvm_type(g, var->var_type), 0)); - } else { - global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); - // TODO debug info for the extern variable - - LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true)); - maybe_import_dll(g, global_value, GlobalLinkageIdStrong); - LLVMSetAlignment(global_value, var->align_bytes); - LLVMSetGlobalConstant(global_value, var->gen_is_const); - set_global_tls(g, var, global_value); - } - } else { - bool exported = (linkage != GlobalLinkageIdInternal); - render_const_val(g, var->const_value, symbol_name); - render_const_val_global(g, var->const_value, symbol_name); - global_value = var->const_value->llvm_global; - - if (exported) { - LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false)); - maybe_export_dll(g, global_value, GlobalLinkageIdStrong); - } - if (var->section_name) { - LLVMSetSection(global_value, buf_ptr(var->section_name)); - } - LLVMSetAlignment(global_value, var->align_bytes); - - // TODO debug info for function pointers - // Here we use const_value->type because that's the type of the llvm global, - // which we const ptr cast upon use to whatever it needs to be. - if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) { - gen_global_var(g, var, var->const_value->llvm_value, var->const_value->type); - } - - LLVMSetGlobalConstant(global_value, var->gen_is_const); - set_global_tls(g, var, global_value); - } - - var->value_ref = global_value; - - for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { - GlobalExport *global_export = &var->export_list.items[export_i]; - LLVMAddAlias2(g->module, LLVMTypeOf(var->value_ref), 0, var->value_ref, buf_ptr(&global_export->name)); - } - } - - // Generate function definitions. - stage2_progress_update_node(g->sub_progress_node, 0, g->fn_defs.length); - for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { - ZigFn *fn_table_entry = g->fn_defs.at(fn_i); - Stage2ProgressNode *fn_prog_node = stage2_progress_start(g->sub_progress_node, - buf_ptr(&fn_table_entry->symbol_name), buf_len(&fn_table_entry->symbol_name), 0); - - FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; - CallingConvention cc = fn_type_id->cc; - bool is_c_abi = !calling_convention_allows_zig_types(cc); - bool want_sret = want_first_arg_sret(g, fn_type_id); - - LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); - g->cur_fn = fn_table_entry; - g->cur_fn_val = fn; - - build_all_basic_blocks(g, fn_table_entry); - clear_debug_source_node(g); - - bool is_async = fn_is_async(fn_table_entry); - - if (is_async) { - g->cur_frame_ptr = LLVMGetParam(fn, 0); - } else { - if (want_sret) { - g->cur_ret_ptr = LLVMGetParam(fn, 0); - } else if (type_has_bits(g, fn_type_id->return_type)) { - g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0); - // TODO add debug info variable for this - } else { - g->cur_ret_ptr = nullptr; - } - } - - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); - bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; - if (have_err_ret_trace_arg) { - g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); - } else { - g->cur_err_ret_trace_val_arg = nullptr; - } - - // error return tracing setup - bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && - !is_async && !have_err_ret_trace_arg; - LLVMValueRef err_ret_array_val = nullptr; - if (have_err_ret_trace_stack) { - ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr); - err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); - - (void)get_llvm_type(g, get_stack_trace_type(g)); - g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace", - get_abi_alignment(g, g->stack_trace_type)); - } else { - g->cur_err_ret_trace_val_stack = nullptr; - } - - if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, fn_type_id->return_type); - fn_table_entry->abi_return_value = LLVMBuildAlloca(g->builder, abi_type, ""); - } - - if (!is_async) { - // allocate async frames for nosuspend calls & awaits to async functions - ZigType *largest_call_frame_type = nullptr; - Stage1AirInst *all_calls_alloca = ir_create_alloca(g, &fn_table_entry->fndef_scope->base, - fn_table_entry->body_node, fn_table_entry, g->builtin_types.entry_void, "@async_call_frame"); - for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) { - Stage1AirInstCall *call = fn_table_entry->call_list.at(i); - if (call->fn_entry == nullptr) - continue; - if (!fn_is_async(call->fn_entry)) - continue; - if (call->modifier != CallModifierNoSuspend) - continue; - if (call->frame_result_loc != nullptr) - continue; - ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry); - if (largest_call_frame_type == nullptr || - callee_frame_type->abi_size > largest_call_frame_type->abi_size) - { - largest_call_frame_type = callee_frame_type; - } - call->frame_result_loc = all_calls_alloca; - } - if (largest_call_frame_type != nullptr) { - all_calls_alloca->value->type = get_pointer_to_type(g, largest_call_frame_type, false); - } - // allocate temporary stack data - for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = ptr_type->data.pointer.child_type; - if (type_resolve(g, child_type, ResolveStatusSizeKnown)) - zig_unreachable(); - if (!type_has_bits(g, child_type)) - continue; - if (instruction->base.ref_count == 0) - continue; - if (instruction->base.value->special != ConstValSpecialRuntime) { - if (const_ptr_pointee(nullptr, g, instruction->base.value, nullptr)->special != - ConstValSpecialRuntime) - { - continue; - } - } - if (type_resolve(g, child_type, ResolveStatusLLVMFull)) - zig_unreachable(); - instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint, - get_ptr_align(g, ptr_type)); - } - } - - ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base); - unsigned gen_i_init = want_sret ? 1 : 0; - - // create debug variable declarations for variables and allocate all local variables - FnWalk fn_walk_var = {}; - fn_walk_var.id = FnWalkIdVars; - fn_walk_var.data.vars.import = import; - fn_walk_var.data.vars.fn = fn_table_entry; - fn_walk_var.data.vars.llvm_fn = fn; - fn_walk_var.data.vars.gen_i = gen_i_init; - for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { - ZigVar *var = fn_table_entry->variable_list.at(var_i); - - if (!type_has_bits(g, var->var_type)) { - continue; - } - if (ir_get_var_is_comptime(var)) - continue; - switch (type_requires_comptime(g, var->var_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeYes: - continue; - case ReqCompTimeNo: - break; - } - - if (var->src_arg_index == SIZE_MAX) { - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); - - } else if (is_c_abi) { - fn_walk_var.data.vars.var = var; - iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index); - } else if (!is_async) { - ZigType *gen_type; - FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; - assert(gen_info->gen_index != SIZE_MAX); - - if (handle_is_ptr(g, var->var_type)) { - if (gen_info->is_byval) { - gen_type = var->var_type; - } else { - gen_type = gen_info->type; - } - var->value_ref = LLVMGetParam(fn, gen_info->gen_index); - } else { - gen_type = var->var_type; - var->value_ref = build_alloca(g, var->var_type, var->name, var->align_bytes); - } - if (var->decl_node) { - var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, gen_type), !g->strip_debug_symbols, 0, (unsigned)(gen_info->gen_index+1)); - } - - } - } - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - // finishing error return trace setup. we have to do this after all the allocas. - if (have_err_ret_trace_stack) { - ZigType *usize = g->builtin_types.entry_usize; - size_t index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - LLVMValueRef index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); - gen_store_untyped(g, LLVMConstNull(usize->llvm_type), index_field_ptr, 0, false); - - size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); - - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)ptr_field_index, ""); - LLVMValueRef zero = LLVMConstNull(usize->llvm_type); - LLVMValueRef indices[] = {zero, zero}; - LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP2(g->builder, - LLVMGetAllocatedType(err_ret_array_val), err_ret_array_val, indices, 2, ""); - ZigType *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false); - gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type); - - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)len_field_index, ""); - gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); - } - - if (is_async) { - (void)get_llvm_type(g, fn_table_entry->frame_type); - g->cur_resume_block_count = 0; - - LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); - if (g->need_frame_size_prefix_data) { - ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); - } - - if (!g->strip_debug_symbols) { - AstNode *source_node = fn_table_entry->proto_node; - ZigLLVMSetCurrentDebugLocation(g->builder, - node_line_onebased(source_node), node_column_onebased(source_node), - get_di_scope(g, fn_table_entry->child_scope)); - } - Stage1Air *executable = &fn_table_entry->analyzed_executable; - LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); - LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); - gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope); - - LLVMPositionBuilderAtEnd(g->builder, g->cur_preamble_llvm_block); - render_async_spills(g); - g->cur_async_awaiter_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_awaiter_index, ""); - LLVMValueRef resume_index_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_resume_index, ""); - g->cur_async_resume_index_ptr = resume_index_ptr; - - if (type_has_bits(g, fn_type_id->return_type)) { - LLVMValueRef cur_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_ret_start, ""); - g->cur_ret_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(cur_ret_ptr_ptr), cur_ret_ptr_ptr, ""); - } - uint32_t trace_field_index_stack = UINT32_MAX; - if (codegen_fn_has_err_ret_tracing_stack(g, fn_table_entry, true)) { - trace_field_index_stack = frame_index_trace_stack(g, fn_table_entry); - g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack, ""); - } - - LLVMValueRef resume_index = LLVMBuildLoad2(g->builder, usize_type_ref, resume_index_ptr, ""); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4); - g->cur_async_switch_instr = switch_instr; - - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - Stage1AirBasicBlock *entry_block = executable->basic_block_list.at(0); - LLVMAddCase(switch_instr, zero, entry_block->llvm_block); - g->cur_resume_block_count += 1; - - { - LLVMBasicBlockRef bad_not_suspended_bb = LLVMAppendBasicBlock(g->cur_fn_val, "NotSuspended"); - size_t new_block_index = g->cur_resume_block_count; - g->cur_resume_block_count += 1; - g->cur_bad_not_suspended_index = LLVMConstInt(usize_type_ref, new_block_index, false); - LLVMAddCase(g->cur_async_switch_instr, g->cur_bad_not_suspended_index, bad_not_suspended_bb); - - LLVMPositionBuilderAtEnd(g->builder, bad_not_suspended_bb); - gen_assertion_scope(g, PanicMsgIdResumeNotSuspendedFn, fn_table_entry->child_scope); - } - - LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - if (trace_field_index_stack != UINT32_MAX) { - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - frame_index_trace_arg(g, fn_type_id->return_type), ""); - LLVMValueRef zero_ptr = LLVMConstNull(ZigLLVMGetGEPResultElementType(trace_ptr_ptr)); - LLVMBuildStore(g->builder, zero_ptr, trace_ptr_ptr); - } - - LLVMValueRef trace_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack, ""); - LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack + 1, ""); - - gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr); - } - render_async_var_decls(g, entry_block->instruction_list.at(0)->scope); - } else { - // create debug variable declarations for parameters - // rely on the first variables in the variable_list being parameters. - FnWalk fn_walk_init = {}; - fn_walk_init.id = FnWalkIdInits; - fn_walk_init.data.inits.fn = fn_table_entry; - fn_walk_init.data.inits.llvm_fn = fn; - fn_walk_init.data.inits.gen_i = gen_i_init; - walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init); - } - - ir_render(g, fn_table_entry); - - stage2_progress_end(fn_prog_node); - } - - assert(!g->errors.length); - - if (buf_len(&g->global_asm) != 0) { - LLVMSetModuleInlineAsm2(g->module, buf_ptr(&g->global_asm), buf_len(&g->global_asm)); - } - - while (g->type_resolve_stack.length != 0) { - ZigType *ty = g->type_resolve_stack.last(); - if (type_resolve(g, ty, ResolveStatusLLVMFull)) - zig_unreachable(); - } - - ZigLLVMDIBuilderFinalize(g->dbuilder); - - if (g->verbose_llvm_ir) { - fflush(stderr); - LLVMDumpModule(g->module); - } - - char *error = nullptr; - if (LLVMVerifyModule(g->module, LLVMReturnStatusAction, &error)) { - zig_panic("broken LLVM module found: %s\nThis is a bug in the Zig compiler.", error); - } -} - -static void zig_llvm_emit_output(CodeGen *g) { - g->pass1_arena->destruct(&heap::c_allocator); - g->pass1_arena = nullptr; - - bool is_small = g->build_mode == BuildModeSmallRelease; - - char *err_msg = nullptr; - const char *asm_filename = nullptr; - const char *bin_filename = nullptr; - const char *llvm_ir_filename = nullptr; - const char *bitcode_filename = nullptr; - - if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path); - if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path); - if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path); - if (buf_len(&g->bitcode_file_output_path) != 0) bitcode_filename = buf_ptr(&g->bitcode_file_output_path); - - // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. - // So we call the entire pipeline multiple times if this is requested. - if (asm_filename != nullptr && bin_filename != nullptr) { - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, - g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, - g->have_lto, nullptr, bin_filename, llvm_ir_filename, nullptr)) - { - fprintf(stderr, "LLVM failed to emit bin=%s, ir=%s: %s\n", - bin_filename, llvm_ir_filename, err_msg); - exit(1); - } - bin_filename = nullptr; - llvm_ir_filename = nullptr; - } - - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, - g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, - g->have_lto, asm_filename, bin_filename, llvm_ir_filename, bitcode_filename)) - { - fprintf(stderr, "LLVM failed to emit asm=%s, bin=%s, ir=%s, bc=%s: %s\n", - asm_filename, bin_filename, llvm_ir_filename, bitcode_filename, - err_msg); - exit(1); - } - - LLVMDisposeModule(g->module); - g->module = nullptr; - LLVMDisposeTargetData(g->target_data_ref); - g->target_data_ref = nullptr; - LLVMDisposeTargetMachine(g->target_machine); - g->target_machine = nullptr; -} - -struct CIntTypeInfo { - CIntType id; - const char *name; - bool is_signed; -}; - -static const CIntTypeInfo c_int_type_infos[] = { - {CIntTypeShort, "c_short", true}, - {CIntTypeUShort, "c_ushort", false}, - {CIntTypeInt, "c_int", true}, - {CIntTypeUInt, "c_uint", false}, - {CIntTypeLong, "c_long", true}, - {CIntTypeULong, "c_ulong", false}, - {CIntTypeLongLong, "c_longlong", true}, - {CIntTypeULongLong, "c_ulonglong", false}, -}; - -static const bool is_signed_list[] = { false, true, }; - -struct GlobalLinkageValue { - GlobalLinkageId id; - const char *name; -}; - -static void add_fp_entry(CodeGen *g, const char *name, uint32_t bit_count, LLVMTypeRef type_ref, - ZigType **field) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdFloat); - entry->llvm_type = type_ref; - entry->size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - buf_init_from_str(&entry->name, name); - entry->data.floating.bit_count = bit_count; - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - entry->size_in_bits, ZigLLVMEncoding_DW_ATE_float()); - *field = entry; - g->primitive_type_table.put(&entry->name, entry); -} - -static void define_builtin_types(CodeGen *g) { - { - // if this type is anywhere in the AST, we should never hit codegen. - ZigType *entry = new_type_table_entry(ZigTypeIdInvalid); - buf_init_from_str(&entry->name, "(invalid)"); - g->builtin_types.entry_invalid = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat); - buf_init_from_str(&entry->name, "comptime_float"); - g->builtin_types.entry_num_lit_float = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdComptimeInt); - buf_init_from_str(&entry->name, "comptime_int"); - g->builtin_types.entry_num_lit_int = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral); - buf_init_from_str(&entry->name, "@Type(.EnumLiteral)"); - g->builtin_types.entry_enum_literal = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdUndefined); - buf_init_from_str(&entry->name, "@Type(.Undefined)"); - g->builtin_types.entry_undef = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdNull); - buf_init_from_str(&entry->name, "@Type(.Null)"); - g->builtin_types.entry_null = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); - buf_init_from_str(&entry->name, "(anytype)"); - g->builtin_types.entry_anytype = entry; - } - - for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) { - const CIntTypeInfo *info = &c_int_type_infos[i]; - uint32_t size_in_bits = target_c_type_size_in_bits(g->zig_target, info->id); - bool is_signed = info->is_signed; - - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - entry->llvm_type = LLVMIntType(size_in_bits); - entry->size_in_bits = size_in_bits; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - buf_init_from_str(&entry->name, info->name); - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - size_in_bits, - is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned()); - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = size_in_bits; - g->primitive_type_table.put(&entry->name, entry); - - get_c_int_type_ptr(g, info->id)[0] = entry; - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdBool); - entry->llvm_type = LLVMInt1Type(); - entry->size_in_bits = 1; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - buf_init_from_str(&entry->name, "bool"); - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 1, ZigLLVMEncoding_DW_ATE_boolean()); - g->builtin_types.entry_bool = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - for (size_t sign_i = 0; sign_i < array_length(is_signed_list); sign_i += 1) { - bool is_signed = is_signed_list[sign_i]; - - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - entry->llvm_type = LLVMIntType(g->pointer_size_bytes * 8); - entry->size_in_bits = g->pointer_size_bytes * 8; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - const char u_or_i = is_signed ? 'i' : 'u'; - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%csize", u_or_i); - - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = g->pointer_size_bytes * 8; - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 8*LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type), - is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned()); - g->primitive_type_table.put(&entry->name, entry); - - if (is_signed) { - g->builtin_types.entry_isize = entry; - } else { - g->builtin_types.entry_usize = entry; - } - } - - if (target_is_arm(g->zig_target)) { - add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16); - } else { - ZigType *u16_ty = get_int_type(g, false, 16); - add_fp_entry(g, "f16", 16, get_llvm_type(g, u16_ty), &g->builtin_types.entry_f16); - } - add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32); - add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64); - add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128); - - { - ZigType *entry = new_type_table_entry(ZigTypeIdFloat); - entry->size_in_bits = 80; - - buf_init_from_str(&entry->name, "f80"); - entry->data.floating.bit_count = 80; - - if (target_has_f80(g->zig_target)) { - entry->llvm_type = LLVMX86FP80Type(); - - // Note the following u64 alignments: - // x86-linux: 4 - // x86-windows: 8 - // LLVM makes x86_fp80 have the following alignment and sizes regardless - // of operating system: - // x86_64: size=16, align=16 - // x86: size=12, align=4 - // However in Zig we override x86-windows to have size=16, align=16 - // in order for the property to hold that u80 and f80 have the same ABI size. - unsigned u64_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMInt64Type()); - - if (u64_alignment >= 8) { - entry->abi_size = 16; - entry->abi_align = 16; - } else if (u64_alignment >= 4) { - entry->abi_size = 12; - entry->abi_align = 4; - } else { - entry->abi_size = 10; - entry->abi_align = u64_alignment; - } - } else { - // We use an int here instead of x86_fp80 because on targets such as arm, - // LLVM will give "ERROR: Cannot select" for any instructions involving - // the x86_fp80 type. - ZigType *u80_ty = get_int_type(g, false, 80); - assert(!target_has_f80(g->zig_target)); - assert(u80_ty->size_in_bits == entry->size_in_bits); - entry->llvm_type = get_llvm_type(g, u80_ty); - entry->abi_size = u80_ty->abi_size; - entry->abi_align = u80_ty->abi_align; - } - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - entry->size_in_bits, ZigLLVMEncoding_DW_ATE_unsigned()); - - g->builtin_types.entry_f80 = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - if (g->zig_target->abi != ZigLLVM_MSVC) { - add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble); - g->builtin_types.entry_c_longdouble->abi_size = g->builtin_types.entry_f80->abi_size; - g->builtin_types.entry_c_longdouble->abi_align = g->builtin_types.entry_f80->abi_align; - } else { - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - } - break; - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - if (g->zig_target->os == OsWindows || target_os_is_darwin(g->zig_target->os)) - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - else - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_mips: - case ZigLLVM_mipsel: - // Assume o32 ABI - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_sparcv9: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_systemz: - add_fp_entry(g, "c_longdouble", 128, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_avr: - // It's either a float or a double, depending on a toolchain switch - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_msp430: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - default: - zig_panic("TODO implement mapping for c_longdouble"); - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdVoid); - entry->llvm_type = LLVMVoidType(); - buf_init_from_str(&entry->name, "void"); - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 0, - ZigLLVMEncoding_DW_ATE_signed()); - g->builtin_types.entry_void = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdUnreachable); - entry->llvm_type = LLVMVoidType(); - buf_init_from_str(&entry->name, "noreturn"); - entry->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - g->builtin_types.entry_unreachable = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdMetaType); - buf_init_from_str(&entry->name, "type"); - g->builtin_types.entry_type = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - g->builtin_types.entry_u8 = get_int_type(g, false, 8); - g->builtin_types.entry_u16 = get_int_type(g, false, 16); - g->builtin_types.entry_u29 = get_int_type(g, false, 29); - g->builtin_types.entry_u32 = get_int_type(g, false, 32); - g->builtin_types.entry_u64 = get_int_type(g, false, 64); - g->builtin_types.entry_i8 = get_int_type(g, true, 8); - g->builtin_types.entry_i32 = get_int_type(g, true, 32); - g->builtin_types.entry_i64 = get_int_type(g, true, 64); - - { - g->builtin_types.entry_anyopaque = get_opaque_type(g, nullptr, nullptr, "anyopaque", - buf_create_from_str("anyopaque")); - g->primitive_type_table.put(&g->builtin_types.entry_anyopaque->name, g->builtin_types.entry_anyopaque); - } - - { - ZigType *ptr_const_anyopaque = get_pointer_to_type(g, - g->builtin_types.entry_anyopaque, true); - g->builtin_types.entry_opt_ptr_const_anyopaque = get_optional_type(g, ptr_const_anyopaque); - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdErrorSet); - buf_init_from_str(&entry->name, "anyerror"); - entry->data.error_set.err_count = UINT32_MAX; - - // TODO https://github.com/ziglang/zig/issues/786 - g->err_tag_type = g->builtin_types.entry_u16; - - entry->size_in_bits = g->err_tag_type->size_in_bits; - entry->abi_align = g->err_tag_type->abi_align; - entry->abi_size = g->err_tag_type->abi_size; - - g->builtin_types.entry_global_error_set = entry; - - g->errors_by_index.append(nullptr); - - g->primitive_type_table.put(&entry->name, entry); - } -} - -static void define_intern_values(CodeGen *g) { - { - auto& value = g->intern.x_undefined; - value.type = g->builtin_types.entry_undef; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_void; - value.type = g->builtin_types.entry_void; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_null; - value.type = g->builtin_types.entry_null; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_unreachable; - value.type = g->builtin_types.entry_unreachable; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.zero_byte; - value.type = g->builtin_types.entry_u8; - value.special = ConstValSpecialStatic; - bigint_init_unsigned(&value.data.x_bigint, 0); - } -} - -static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) { - BuiltinFnEntry *builtin_fn = heap::c_allocator.create(); - buf_init_from_str(&builtin_fn->name, name); - builtin_fn->id = id; - builtin_fn->param_count = count; - g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); - return builtin_fn; -} - -static void define_builtin_fns(CodeGen *g) { - create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); - create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0); - create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3); - create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); - create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); - create_builtin_fn(g, BuiltinFnIdAlignOf, "alignOf", 1); - create_builtin_fn(g, BuiltinFnIdField, "field", 2); - create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); - create_builtin_fn(g, BuiltinFnIdType, "Type", 1); - create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); - create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdShlWithOverflow, "shlWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1); - create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2); - create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1); - create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1); - create_builtin_fn(g, BuiltinFnIdClz, "clz", 1); - create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1); - create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 1); - create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 1); - create_builtin_fn(g, BuiltinFnIdImport, "import", 1); - create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1); - create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1); - create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1); - create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1); - create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6); - create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6); - create_builtin_fn(g, BuiltinFnIdFence, "fence", 1); - create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2); - create_builtin_fn(g, BuiltinFnIdIntCast, "intCast", 2); - create_builtin_fn(g, BuiltinFnIdFloatCast, "floatCast", 2); - create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2); - create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2); - create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1); - create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1); - create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1); - create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1); - create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2); - create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); - create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); - create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); - create_builtin_fn(g, BuiltinFnIdSelect, "select", 4); - create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); - create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); - create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); - create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); - create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); - create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); - create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); - create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); - create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1); - create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); - create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); - create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); - create_builtin_fn(g, BuiltinFnIdBitOffsetOf, "bitOffsetOf", 2); - create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); - create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2); - create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2); - create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); - create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); - create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 1); - create_builtin_fn(g, BuiltinFnIdSin, "sin", 1); - create_builtin_fn(g, BuiltinFnIdCos, "cos", 1); - create_builtin_fn(g, BuiltinFnIdTan, "tan", 1); - create_builtin_fn(g, BuiltinFnIdExp, "exp", 1); - create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 1); - create_builtin_fn(g, BuiltinFnIdLog, "log", 1); - create_builtin_fn(g, BuiltinFnIdLog2, "log2", 1); - create_builtin_fn(g, BuiltinFnIdLog10, "log10", 1); - create_builtin_fn(g, BuiltinFnIdFabs, "fabs", 1); - create_builtin_fn(g, BuiltinFnIdFloor, "floor", 1); - create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 1); - create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 1); - create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 1); - create_builtin_fn(g, BuiltinFnIdRound, "round", 1); - create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); - create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); - create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); - create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); - create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); - create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); - create_builtin_fn(g, BuiltinFnIdExport, "export", 2); - create_builtin_fn(g, BuiltinFnIdExtern, "extern", 2); - create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); - create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); - create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3); - create_builtin_fn(g, BuiltinFnIdAtomicStore, "atomicStore", 4); - create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2); - create_builtin_fn(g, BuiltinFnIdThis, "This", 0); - create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2); - create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3); - create_builtin_fn(g, BuiltinFnIdFrameHandle, "frame", 0); - create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1); - create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0); - create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1); - create_builtin_fn(g, BuiltinFnIdAs, "as", 2); - create_builtin_fn(g, BuiltinFnIdCall, "call", 3); - create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1); - create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1); - create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2); - create_builtin_fn(g, BuiltinFnIdSrc, "src", 0); - create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); - create_builtin_fn(g, BuiltinFnIdMaximum, "max", 2); - create_builtin_fn(g, BuiltinFnIdMinimum, "min", 2); - create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2); - create_builtin_fn(g, BuiltinFnIdAddrSpaceCast, "addrSpaceCast", 2); -} - -static const char *bool_to_str(bool b) { - return b ? "true" : "false"; -} - -static const char *build_mode_to_str(BuildMode build_mode) { - switch (build_mode) { - case BuildModeDebug: return "Debug"; - case BuildModeSafeRelease: return "ReleaseSafe"; - case BuildModeFastRelease: return "ReleaseFast"; - case BuildModeSmallRelease: return "ReleaseSmall"; - } - zig_unreachable(); -} - -static const char *subsystem_to_str(TargetSubsystem subsystem) { - switch (subsystem) { - case TargetSubsystemConsole: return "Console"; - case TargetSubsystemWindows: return "Windows"; - case TargetSubsystemPosix: return "Posix"; - case TargetSubsystemNative: return "Native"; - case TargetSubsystemEfiApplication: return "EfiApplication"; - case TargetSubsystemEfiBootServiceDriver: return "EfiBootServiceDriver"; - case TargetSubsystemEfiRom: return "EfiRom"; - case TargetSubsystemEfiRuntimeDriver: return "EfiRuntimeDriver"; - case TargetSubsystemAuto: zig_unreachable(); - } - zig_unreachable(); -} - -// Returns TargetSubsystemAuto to mean "no subsystem" -TargetSubsystem detect_subsystem(CodeGen *g) { - if (g->subsystem != TargetSubsystemAuto) - return g->subsystem; - if (g->zig_target->os == OsWindows) { - if (g->stage1.have_dllmain_crt_startup) - return TargetSubsystemAuto; - if (g->stage1.have_c_main || g->is_test_build || g->stage1.have_winmain_crt_startup || g->stage1.have_wwinmain_crt_startup) - return TargetSubsystemConsole; - if (g->stage1.have_winmain || g->stage1.have_wwinmain) - return TargetSubsystemWindows; - } else if (g->zig_target->os == OsUefi) { - return TargetSubsystemEfiApplication; - } - return TargetSubsystemAuto; -} - -static bool detect_err_ret_tracing(CodeGen *g) { - return !g->strip_debug_symbols && - g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease; -} - -static LLVMCodeModel to_llvm_code_model(CodeGen *g) { - switch (g->code_model) { - case CodeModelDefault: - return LLVMCodeModelDefault; - case CodeModelTiny: - return LLVMCodeModelTiny; - case CodeModelSmall: - return LLVMCodeModelSmall; - case CodeModelKernel: - return LLVMCodeModelKernel; - case CodeModelMedium: - return LLVMCodeModelMedium; - case CodeModelLarge: - return LLVMCodeModelLarge; - } - - zig_unreachable(); -} - -Buf *codegen_generate_builtin_source(CodeGen *g) { - // Note that this only runs when zig0 is building the self-hosted zig compiler code, - // so it makes a few assumption that are always true for that case. Once we have - // built the stage2 zig components then zig is in charge of generating the builtin.zig - // file. - - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - Buf *contents = buf_alloc(); - buf_appendf(contents, - "const std = @import(\"std\");\n" - ); - - const char *cur_os = nullptr; - { - uint32_t field_count = (uint32_t)target_os_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - Os os_type = target_os_enum(i); - const char *name = target_os_name(os_type); - - if (os_type == g->zig_target->os) { - cur_os = name; - } - } - } - assert(cur_os != nullptr); - - const char *cur_arch = nullptr; - { - uint32_t field_count = (uint32_t)target_arch_count(); - for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) { - ZigLLVM_ArchType arch = target_arch_enum(arch_i); - const char *arch_name = target_arch_name(arch); - if (arch == g->zig_target->arch) { - cur_arch = arch_name; - } - } - - // Workaround to LLVM/Zig naming mismatch. - // LLVM calls it sparcv9, while Zig calls it sparc64. - if (!strcmp(cur_arch, "sparcv9")) { - cur_arch = "sparc64"; - } - } - assert(cur_arch != nullptr); - - const char *cur_abi = nullptr; - { - uint32_t field_count = (uint32_t)target_abi_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - ZigLLVM_EnvironmentType abi = target_abi_enum(i); - const char *name = target_abi_name(abi); - - if (abi == g->zig_target->abi) { - cur_abi = name; - } - } - } - assert(cur_abi != nullptr); - - const char *cur_obj_fmt = nullptr; - { - uint32_t field_count = (uint32_t)target_oformat_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - ZigLLVM_ObjectFormatType oformat = target_oformat_enum(i); - const char *name = target_oformat_name(oformat); - - ZigLLVM_ObjectFormatType target_oformat = target_object_format(g->zig_target); - if (oformat == target_oformat) { - cur_obj_fmt = name; - } - } - - } - assert(cur_obj_fmt != nullptr); - - // If any of these asserts trip then you need to either fix the internal compiler enum - // or the corresponding one in std.Target or std.builtin. - static_assert(ContainerLayoutAuto == 0, ""); - static_assert(ContainerLayoutExtern == 1, ""); - static_assert(ContainerLayoutPacked == 2, ""); - - static_assert(CallingConventionUnspecified == 0, ""); - static_assert(CallingConventionC == 1, ""); - static_assert(CallingConventionNaked == 2, ""); - static_assert(CallingConventionAsync == 3, ""); - static_assert(CallingConventionInline == 4, ""); - static_assert(CallingConventionInterrupt == 5, ""); - static_assert(CallingConventionSignal == 6, ""); - static_assert(CallingConventionStdcall == 7, ""); - static_assert(CallingConventionFastcall == 8, ""); - static_assert(CallingConventionVectorcall == 9, ""); - static_assert(CallingConventionThiscall == 10, ""); - static_assert(CallingConventionAPCS == 11, ""); - static_assert(CallingConventionAAPCS == 12, ""); - static_assert(CallingConventionAAPCSVFP == 13, ""); - static_assert(CallingConventionSysV == 14, ""); - static_assert(CallingConventionWin64 == 15, ""); - - static_assert(BuiltinPtrSizeOne == 0, ""); - static_assert(BuiltinPtrSizeMany == 1, ""); - static_assert(BuiltinPtrSizeSlice == 2, ""); - static_assert(BuiltinPtrSizeC == 3, ""); - - static_assert(TargetSubsystemConsole == 0, ""); - static_assert(TargetSubsystemWindows == 1, ""); - static_assert(TargetSubsystemPosix == 2, ""); - static_assert(TargetSubsystemNative == 3, ""); - static_assert(TargetSubsystemEfiApplication == 4, ""); - static_assert(TargetSubsystemEfiBootServiceDriver == 5, ""); - static_assert(TargetSubsystemEfiRom == 6, ""); - static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); - - buf_appendf(contents, "pub const output_mode = std.builtin.OutputMode.Obj;\n"); - buf_appendf(contents, "pub const link_mode = std.builtin.LinkMode.%s;\n", ZIG_QUOTE(ZIG_LINK_MODE)); - buf_appendf(contents, "pub const is_test = false;\n"); - buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); - buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi); - buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch); - buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s, .%s);\n", cur_os, cur_arch); - buf_appendf(contents, - "pub const target = std.Target{\n" - " .cpu = cpu,\n" - " .os = os,\n" - " .abi = abi,\n" - " .ofmt = object_format,\n" - "};\n" - ); - - buf_appendf(contents, "pub const object_format = std.Target.ObjectFormat.%s;\n", cur_obj_fmt); - buf_appendf(contents, "pub const mode = std.builtin.Mode.%s;\n", build_mode_to_str(g->build_mode)); - buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc)); - buf_appendf(contents, "pub const link_libcpp = %s;\n", bool_to_str(g->link_libcpp)); - buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); - buf_appendf(contents, "pub const valgrind_support = false;\n"); - buf_appendf(contents, "pub const sanitize_thread = false;\n"); - buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); - buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie)); - buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); - buf_appendf(contents, "pub const code_model = std.builtin.CodeModel.default;\n"); - buf_appendf(contents, "pub const zig_backend = std.builtin.CompilerBackend.stage1;\n"); - - { - TargetSubsystem detected_subsystem = detect_subsystem(g); - if (detected_subsystem != TargetSubsystemAuto) { - buf_appendf(contents, "pub const explicit_subsystem = std.builtin.SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); - } - } - - return contents; -} - -static ZigPackage *create_test_runner_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_lib_dir), "test_runner.zig", ""); -} - -static Error define_builtin_compile_vars(CodeGen *g) { - Error err; - - if (g->std_package == nullptr) - return ErrorNone; - - assert(g->main_pkg); - - const char *builtin_zig_basename = "builtin.zig"; - - Buf *contents; - if (g->builtin_zig_path == nullptr) { - // Then this is zig0 building stage2. We can make many assumptions about the compilation. - Buf *out_dir = buf_alloc(); - os_path_split(&g->o_file_output_path, out_dir, nullptr); - g->builtin_zig_path = buf_alloc(); - os_path_join(out_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path); - - Buf *resolve_paths[] = { g->builtin_zig_path, }; - *g->builtin_zig_path = os_path_resolve(resolve_paths, 1); - - contents = codegen_generate_builtin_source(g); - if ((err = os_write_file(g->builtin_zig_path, contents))) { - fprintf(stderr, "Unable to write file '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err)); - exit(1); - } - - g->compile_var_package = new_package(buf_ptr(out_dir), builtin_zig_basename, "builtin"); - } else { - Buf *resolve_paths[] = { g->builtin_zig_path, }; - *g->builtin_zig_path = os_path_resolve(resolve_paths, 1); - - contents = buf_alloc(); - if ((err = os_fetch_file_path(g->builtin_zig_path, contents))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err)); - exit(1); - } - Buf builtin_dirname = BUF_INIT; - os_path_dirname(g->builtin_zig_path, &builtin_dirname); - g->compile_var_package = new_package(buf_ptr(&builtin_dirname), builtin_zig_basename, "builtin"); - } - - if (g->is_test_build) { - if (g->test_runner_package == nullptr) { - g->test_runner_package = create_test_runner_pkg(g); - } - g->root_pkg = g->test_runner_package; - } else { - g->root_pkg = g->main_pkg; - } - - ZigPackage *compiler_rt_pkg = codegen_create_package(g, buf_ptr(g->zig_lib_dir), - "compiler_rt.zig", "compiler_rt"); - - g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->main_pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->main_pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); - g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->std_package->package_table.put(buf_create_from_str("root"), g->root_pkg); - g->std_package->package_table.put(buf_create_from_str("compiler_rt"), compiler_rt_pkg); - g->compile_var_import = add_source_file(g, g->compile_var_package, g->builtin_zig_path, contents, - SourceKindPkgMain); - - return ErrorNone; -} - -static void init(CodeGen *g) { - if (g->module) - return; - - codegen_add_time_event(g, "Initialize"); - { - const char *progress_name = "Initialize"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - assert(g->root_out_name); - g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); - - LLVMSetTarget(g->module, buf_ptr(&g->llvm_triple_str)); - - if (target_object_format(g->zig_target) == ZigLLVM_COFF) { - ZigLLVMAddModuleCodeViewFlag(g->module); - } else { - ZigLLVMAddModuleDebugInfoFlag(g->module); - } - - LLVMTargetRef target_ref; - char *err_msg = nullptr; - if (LLVMGetTargetFromTriple(buf_ptr(&g->llvm_triple_str), &target_ref, &err_msg)) { - fprintf(stderr, - "Zig is expecting LLVM to understand this target: '%s'\n" - "However LLVM responded with: \"%s\"\n" - "Zig is unable to continue. This is a bug in Zig:\n" - "https://github.com/ziglang/zig/issues/438\n" - , buf_ptr(&g->llvm_triple_str), err_msg); - exit(1); - } - - bool is_optimized = g->build_mode != BuildModeDebug; - LLVMCodeGenOptLevel opt_level = is_optimized ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; - - LLVMRelocMode reloc_mode; - if (g->have_pic) { - reloc_mode = LLVMRelocPIC; - } else if (g->link_mode_dynamic) { - reloc_mode = LLVMRelocDynamicNoPic; - } else { - reloc_mode = LLVMRelocStatic; - } - - if (g->have_pic) { - ZigLLVMSetModulePICLevel(g->module); - } - - if (g->have_pie) { - ZigLLVMSetModulePIELevel(g->module); - } - - if (g->code_model != CodeModelDefault) { - ZigLLVMSetModuleCodeModel(g->module, to_llvm_code_model(g)); - } - - const char *target_specific_cpu_args = ""; - const char *target_specific_features = ""; - - if (g->zig_target->is_native_cpu) { - target_specific_cpu_args = ZigLLVMGetHostCPUName(); - target_specific_features = ZigLLVMGetNativeFeatures(); - } - - // Override CPU and features if defined by user. - if (g->zig_target->llvm_cpu_name != nullptr) { - target_specific_cpu_args = g->zig_target->llvm_cpu_name; - } - if (g->zig_target->llvm_cpu_features != nullptr) { - target_specific_features = g->zig_target->llvm_cpu_features; - } - if (g->verbose_llvm_cpu_features) { - fprintf(stderr, "name=%s triple=%s\n", buf_ptr(g->root_out_name), buf_ptr(&g->llvm_triple_str)); - fprintf(stderr, "name=%s target_specific_cpu_args=%s\n", buf_ptr(g->root_out_name), target_specific_cpu_args); - fprintf(stderr, "name=%s target_specific_features=%s\n", buf_ptr(g->root_out_name), target_specific_features); - } - - // TODO handle float ABI better- it should depend on the ABI portion of std.Target - ZigLLVMABIType float_abi = ZigLLVMABITypeDefault; - - const char *abi_name = g->zig_target->llvm_target_abi; - if (abi_name == nullptr && target_is_riscv(g->zig_target)) { - // RISC-V Linux defaults to ilp32d/lp64d - if (g->zig_target->os == OsLinux) { - abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32d" : "lp64d"; - } else { - abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64"; - } - } - - g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), - target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, - to_llvm_code_model(g), g->function_sections, float_abi, abi_name); - - g->target_data_ref = LLVMCreateTargetDataLayout(g->target_machine); - - char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref); - LLVMSetDataLayout(g->module, layout_str); - - assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); - g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); - - g->builder = LLVMCreateBuilder(); - g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true); - - // Don't use the version string here, llvm misparses it when it includes the git revision. - Stage2SemVer semver = stage2_version(); - Buf *producer = buf_sprintf("zig %d.%d.%d", semver.major, semver.minor, semver.patch); - const char *flags = ""; - unsigned runtime_version = 0; - - // For macOS stack traces, we want to avoid having to parse the compilation unit debug - // info. As long as each debug info file has a path independent of the compilation unit - // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug - // info. If we provide an absolute path to LLVM here for the compilation unit debug info, - // LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "." - // for the compilation unit directory. This forces each debug file to have a directory - // rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will - // no longer reference DW_AT_comp_dir, for the purpose of being able to support the - // common practice of stripping all but the line number sections from an executable. - const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." : - buf_ptr(&g->main_pkg->root_src_dir); - - ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), - compile_unit_dir); - g->compile_unit = ZigLLVMCreateCompileUnit(g->dbuilder, ZigLLVMLang_DW_LANG_C99(), - compile_unit_file, buf_ptr(producer), is_optimized, flags, runtime_version, - "", 0, !g->strip_debug_symbols); - - // This is for debug stuff that doesn't have a real file. - g->dummy_di_file = nullptr; - - define_builtin_types(g); - define_intern_values(g); - - Stage1AirInst *sentinel_instructions = heap::c_allocator.allocate(2); - g->invalid_inst_gen = &sentinel_instructions[0]; - g->invalid_inst_gen->value = g->pass1_arena->create(); - g->invalid_inst_gen->value->type = g->builtin_types.entry_invalid; - - g->unreach_instruction = &sentinel_instructions[1]; - g->unreach_instruction->value = g->pass1_arena->create(); - g->unreach_instruction->value->type = g->builtin_types.entry_unreachable; - - g->invalid_inst_src = heap::c_allocator.create(); - - define_builtin_fns(g); - Error err; - if ((err = define_builtin_compile_vars(g))) { - fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err)); - exit(1); - } -} - -static void update_test_functions_builtin_decl(CodeGen *g) { - Error err; - - assert(g->is_test_build); - - if (g->test_fns.length == 0) { - fprintf(stderr, "No tests to run.\n"); - exit(0); - } - - ZigType *fn_type = get_test_fn_type(g); - - ZigValue *test_fn_type_val = get_builtin_value(g, "TestFn"); - assert(test_fn_type_val->type->id == ZigTypeIdMetaType); - ZigType *struct_type = test_fn_type_val->data.x_type; - if ((err = type_resolve(g, struct_type, ResolveStatusSizeKnown))) - zig_unreachable(); - - ZigValue *test_fn_array = g->pass1_arena->create(); - test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, nullptr); - test_fn_array->special = ConstValSpecialStatic; - test_fn_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(g->test_fns.length); - - for (size_t i = 0; i < g->test_fns.length; i += 1) { - ZigFn *test_fn_entry = g->test_fns.at(i); - - ZigValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; - this_val->special = ConstValSpecialStatic; - this_val->type = struct_type; - this_val->parent.id = ConstParentIdArray; - this_val->parent.data.p_array.array_val = test_fn_array; - this_val->parent.data.p_array.elem_index = i; - this_val->data.x_struct.fields = alloc_const_vals_ptrs(g, 3); - - ZigValue *name_field = this_val->data.x_struct.fields[0]; - ZigValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, name_field, name_array_val, 0, buf_len(&test_fn_entry->symbol_name), true, nullptr); - - ZigValue *fn_field = this_val->data.x_struct.fields[1]; - fn_field->type = fn_type; - fn_field->special = ConstValSpecialStatic; - fn_field->data.x_ptr.special = ConstPtrSpecialFunction; - fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst; - fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry; - - ZigValue *frame_size_field = this_val->data.x_struct.fields[2]; - frame_size_field->type = get_optional_type(g, g->builtin_types.entry_usize); - frame_size_field->special = ConstValSpecialStatic; - frame_size_field->data.x_optional = nullptr; - - if (fn_is_async(test_fn_entry)) { - frame_size_field->data.x_optional = g->pass1_arena->create(); - frame_size_field->data.x_optional->special = ConstValSpecialStatic; - frame_size_field->data.x_optional->type = g->builtin_types.entry_usize; - bigint_init_unsigned(&frame_size_field->data.x_optional->data.x_bigint, - test_fn_entry->frame_type->abi_size); - } - } - report_errors_and_maybe_exit(g); - - ZigValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true, nullptr); - - update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice); - assert(g->test_runner_package != nullptr); -} - -static Buf *get_resolved_root_src_path(CodeGen *g) { - // TODO memoize - if (buf_len(&g->main_pkg->root_src_path) == 0) - return nullptr; - - Buf rel_full_path = BUF_INIT; - os_path_join(&g->main_pkg->root_src_dir, &g->main_pkg->root_src_path, &rel_full_path); - - Buf *resolved_path = buf_alloc(); - Buf *resolve_paths[] = {&rel_full_path}; - *resolved_path = os_path_resolve(resolve_paths, 1); - - return resolved_path; -} - -static void gen_root_source(CodeGen *g) { - Buf *resolved_path = get_resolved_root_src_path(g); - if (resolved_path == nullptr) - return; - - Buf *source_code = buf_alloc(); - Error err; - // No need for using the caching system for this file fetch because it is handled - // separately. - if ((err = os_fetch_file_path(resolved_path, source_code))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err)); - exit(1); - } - - ZigType *root_import_alias = add_source_file(g, g->main_pkg, resolved_path, source_code, SourceKindRoot); - assert(root_import_alias == g->root_import); - - assert(g->root_out_name); - - // Zig has lazy top level definitions. Here we semantically analyze the panic function. - Buf *import_target_path; - Buf full_path = BUF_INIT; - ZigType *std_import; - if ((err = analyze_import(g, g->root_import, buf_create_from_str("std"), &std_import, - &import_target_path, &full_path))) - { - if (err == ErrorFileNotFound) { - fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path)); - } else { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); - } - exit(1); - } - - Tld *builtin_tld = find_decl(g, &get_container_scope(std_import)->base, - buf_create_from_str("builtin")); - assert(builtin_tld != nullptr); - resolve_top_level_decl(g, builtin_tld, nullptr, false); - report_errors_and_maybe_exit(g); - assert(builtin_tld->id == TldIdVar); - TldVar *builtin_tld_var = (TldVar*)builtin_tld; - ZigValue *builtin_val = builtin_tld_var->var->const_value; - assert(builtin_val->type->id == ZigTypeIdMetaType); - g->std_builtin_import = builtin_val->data.x_type; - - Tld *panic_tld = find_decl(g, &get_container_scope(g->std_builtin_import)->base, - buf_create_from_str("panic")); - assert(panic_tld != nullptr); - resolve_top_level_decl(g, panic_tld, nullptr, false); - report_errors_and_maybe_exit(g); - assert(panic_tld->id == TldIdVar); - TldVar *panic_tld_var = (TldVar*)panic_tld; - ZigValue *panic_fn_val = panic_tld_var->var->const_value; - assert(panic_fn_val->type->id == ZigTypeIdFn); - assert(panic_fn_val->data.x_ptr.special == ConstPtrSpecialFunction); - g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry; - assert(g->panic_fn != nullptr); - - if (g->include_compiler_rt) { - Buf *import_target_path; - Buf full_path = BUF_INIT; - ZigType *compiler_rt_import; - if ((err = analyze_import(g, std_import, buf_create_from_str("compiler_rt"), - &compiler_rt_import, &import_target_path, &full_path))) - { - if (err == ErrorFileNotFound) { - fprintf(stderr, "unable to find '%s'\n", buf_ptr(import_target_path)); - } else { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); - } - exit(1); - } - } - - if (!g->error_during_imports) { - semantic_analyze(g); - } - report_errors_and_maybe_exit(g); - - if (g->is_test_build) { - update_test_functions_builtin_decl(g); - if (!g->error_during_imports) { - semantic_analyze(g); - } - } - - report_errors_and_maybe_exit(g); - -} - -void codegen_print_timing_report(CodeGen *g, FILE *f) { - double start_time = g->timing_events.at(0).time; - double end_time = g->timing_events.last().time; - double total = end_time - start_time; - fprintf(f, "%20s%12s%12s%12s%12s\n", "Name", "Start", "End", "Duration", "Percent"); - for (size_t i = 0; i < g->timing_events.length - 1; i += 1) { - TimeEvent *te = &g->timing_events.at(i); - TimeEvent *next_te = &g->timing_events.at(i + 1); - fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", te->name, - te->time - start_time, - next_te->time - start_time, - next_te->time - te->time, - (next_te->time - te->time) / total); - } - fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", "Total", 0.0, total, total, 1.0); -} - -void codegen_add_time_event(CodeGen *g, const char *name) { - OsTimeStamp timestamp = os_timestamp_monotonic(); - double seconds = (double)timestamp.sec; - seconds += ((double)timestamp.nsec) / 1000000000.0; - g->timing_events.append({seconds, name}); -} - -void codegen_build_object(CodeGen *g) { - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - init(g); - - codegen_add_time_event(g, "Semantic Analysis"); - const char *progress_name = "Semantic Analysis"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - - gen_root_source(g); - - - codegen_add_time_event(g, "Code Generation"); - { - const char *progress_name = "Code Generation"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - - do_code_gen(g); - codegen_add_time_event(g, "LLVM Emit Object"); - { - const char *progress_name = "LLVM Emit Object"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - zig_llvm_emit_output(g); - - codegen_add_time_event(g, "Done"); - codegen_switch_sub_prog_node(g, nullptr); - - // append all export symbols to stage2 so we can provide them to the linker - if (target_is_wasm(g->zig_target)){ - Error err; - auto export_it = g->exported_symbol_names.entry_iterator(); - decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; - while ((curr_entry = export_it.next()) != nullptr) { - if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) { - fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err)); - } - } - } -} - -ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, - const char *pkg_path) -{ - init(g); - ZigPackage *pkg = new_package(root_src_dir, root_src_path, pkg_path); - if (g->std_package != nullptr) { - assert(g->compile_var_package != nullptr); - pkg->package_table.put(buf_create_from_str("std"), g->std_package); - - pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); - - pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - } - return pkg; -} - -void codegen_destroy(CodeGen *g) { - if (g->pass1_arena != nullptr) { - g->pass1_arena->destruct(&heap::c_allocator); - g->pass1_arena = nullptr; - } - heap::c_allocator.destroy(g); -} - -CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - BuildMode build_mode, Buf *override_lib_dir, - bool is_test_build) -{ - CodeGen *g = heap::c_allocator.create(); - g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1"); - - g->subsystem = TargetSubsystemAuto; - g->zig_target = target; - - assert(override_lib_dir != nullptr); - g->zig_lib_dir = override_lib_dir; - - g->zig_std_dir = buf_alloc(); - os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); - - g->build_mode = build_mode; - g->import_table.init(32); - g->builtin_fn_table.init(32); - g->primitive_type_table.init(32); - g->type_table.init(32); - g->fn_type_table.init(32); - g->error_table.init(16); - g->generic_table.init(16); - g->llvm_fn_table.init(16); - g->memoized_fn_eval_table.init(16); - g->exported_symbol_names.init(8); - g->external_symbol_names.init(8); - g->string_literals_table.init(16); - g->type_info_cache.init(32); - g->one_possible_values.init(32); - g->is_test_build = is_test_build; - g->is_single_threaded = false; - g->code_model = CodeModelDefault; - buf_resize(&g->global_asm, 0); - - for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { - g->external_symbol_names.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr); - } - - if (root_src_path) { - Buf *root_pkg_path; - Buf *rel_root_src_path; - if (main_pkg_path == nullptr) { - Buf *src_basename = buf_alloc(); - Buf *src_dir = buf_alloc(); - os_path_split(root_src_path, src_dir, src_basename); - - if (buf_len(src_basename) == 0) { - fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path)); - exit(1); - } - root_pkg_path = src_dir; - rel_root_src_path = src_basename; - } else { - Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1); - Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1); - - if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) { - fprintf(stderr, "Root source path '%s' outside main package path '%s'\n", - buf_ptr(root_src_path), buf_ptr(main_pkg_path)); - exit(1); - } - root_pkg_path = main_pkg_path; - rel_root_src_path = buf_create_from_mem( - buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1, - buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1); - } - - g->main_pkg = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); - g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std"); - g->main_pkg->package_table.put(buf_create_from_str("std"), g->std_package); - } else { - g->main_pkg = new_package(".", "", ""); - } - - target_triple_llvm(&g->llvm_triple_str, g->zig_target); - g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; - - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } - - return g; -} - -bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type) { - return g->have_err_ret_tracing && - (return_type->id == ZigTypeIdErrorUnion || - return_type->id == ZigTypeIdErrorSet); -} - -bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async) { - if (is_async) { - return g->have_err_ret_tracing && (fn->calls_or_awaits_errorable_fn || - codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type)); - } else { - return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn && - !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type); - } -} - -void codegen_switch_sub_prog_node(CodeGen *g, Stage2ProgressNode *node) { - if (g->sub_progress_node != nullptr) { - stage2_progress_end(g->sub_progress_node); - } - g->sub_progress_node = node; -} - -ZigValue *CodeGen::Intern::for_undefined() { - return &this->x_undefined; -} - -ZigValue *CodeGen::Intern::for_void() { - return &this->x_void; -} - -ZigValue *CodeGen::Intern::for_null() { - return &this->x_null; -} - -ZigValue *CodeGen::Intern::for_unreachable() { - return &this->x_unreachable; -} - -ZigValue *CodeGen::Intern::for_zero_byte() { - return &this->zero_byte; -} diff --git a/src/stage1/codegen.hpp b/src/stage1/codegen.hpp deleted file mode 100644 index 33b2f7475794..000000000000 --- a/src/stage1/codegen.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_CODEGEN_HPP -#define ZIG_CODEGEN_HPP - -#include "parser.hpp" -#include "errmsg.hpp" -#include "target.hpp" -#include "stage2.h" - -#include - -CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - BuildMode build_mode, Buf *zig_lib_dir, bool is_test_build); - -void codegen_build_object(CodeGen *g); -void codegen_destroy(CodeGen *); - -void codegen_add_time_event(CodeGen *g, const char *name); -void codegen_print_timing_report(CodeGen *g, FILE *f); - -ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, - const char *pkg_path); - -TargetSubsystem detect_subsystem(CodeGen *g); - -bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type); -bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async); - -ATTRIBUTE_NORETURN -void codegen_report_errors_and_exit(CodeGen *g); - -void codegen_switch_sub_prog_node(CodeGen *g, Stage2ProgressNode *node); - -#endif diff --git a/src/stage1/config.h.in b/src/stage1/config.h.in deleted file mode 100644 index 22311373f69a..000000000000 --- a/src/stage1/config.h.in +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_CONFIG_H -#define ZIG_CONFIG_H - -// Used by zig0.cpp -#define ZIG_VERSION_MAJOR @ZIG_VERSION_MAJOR@ -#define ZIG_VERSION_MINOR @ZIG_VERSION_MINOR@ -#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ -#define ZIG_VERSION_STRING "@RESOLVED_ZIG_VERSION@" - -// Used by build.zig for communicating build information to self hosted build. -#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" -#define ZIG_LLVM_LINK_MODE "@LLVM_LINK_MODE@" -#define ZIG_CMAKE_PREFIX_PATH "@ZIG_CMAKE_PREFIX_PATH@" -#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@" -#define ZIG_LLD_INCLUDE_PATH "@LLD_INCLUDE_DIRS@" -#define ZIG_LLD_LIBRARIES "@LLD_LIBRARIES@" -#define ZIG_CLANG_LIBRARIES "@CLANG_LIBRARIES@" -#define ZIG_LLVM_INCLUDE_PATH "@LLVM_INCLUDE_DIRS@" -#define ZIG_LLVM_LIB_PATH "@LLVM_LIBDIRS@" -#define ZIG_LLVM_LIBRARIES "@LLVM_LIBRARIES@" -#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" - -#endif diff --git a/src/stage1/empty.cpp b/src/stage1/empty.cpp deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/src/stage1/errmsg.cpp b/src/stage1/errmsg.cpp deleted file mode 100644 index 943b118ddbf2..000000000000 --- a/src/stage1/errmsg.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "errmsg.hpp" -#include "os.hpp" - -#include - -enum ErrType { - ErrTypeError, - ErrTypeNote, -}; - -static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) { - bool supports_color = os_stderr_supports_color(); - bool use_colors = color == ErrColorOn || (color == ErrColorAuto && supports_color); - - // Show the error location, if available - if (err->path != nullptr) { - const char *path = buf_ptr(err->path); - Slice pathslice{path, strlen(path)}; - - // Cache cwd - static Buf *cwdbuf{nullptr}; - static Slice cwd; - - if (cwdbuf == nullptr) { - cwdbuf = buf_alloc(); - Error err = os_get_cwd(cwdbuf); - if (err != ErrorNone) - zig_panic("get cwd failed"); - buf_append_char(cwdbuf, ZIG_OS_SEP_CHAR); - cwd.ptr = buf_ptr(cwdbuf); - cwd.len = strlen(cwd.ptr); - } - - const size_t line = err->line_start + 1; - const size_t col = err->column_start + 1; - if (use_colors) os_stderr_set_color(TermColorBold); - - // Strip cwd from path - if (memStartsWith(pathslice, cwd)) - fprintf(stderr, ".%c%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", ZIG_OS_SEP_CHAR, path+cwd.len, line, col); - else - fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col); - } - - // Write out the error type - switch (err_type) { - case ErrTypeError: - if (use_colors) os_stderr_set_color(TermColorRed); - fprintf(stderr, "error: "); - break; - case ErrTypeNote: - if (use_colors) os_stderr_set_color(TermColorCyan); - fprintf(stderr, "note: "); - break; - default: - zig_unreachable(); - } - - // Write out the error message - if (use_colors) os_stderr_set_color(TermColorBold); - fputs(buf_ptr(err->msg), stderr); - if (use_colors) os_stderr_set_color(TermColorReset); - fputc('\n', stderr); - - if (buf_len(&err->line_buf) != 0){ - // Show the referenced line - fprintf(stderr, "%s\n", buf_ptr(&err->line_buf)); - for (size_t i = 0; i < err->column_start; i += 1) { - fprintf(stderr, " "); - } - // Draw the caret - if (use_colors) os_stderr_set_color(TermColorGreen); - fprintf(stderr, "^"); - if (use_colors) os_stderr_set_color(TermColorReset); - fprintf(stderr, "\n"); - } - - for (size_t i = 0; i < err->notes.length; i += 1) { - ErrorMsg *note = err->notes.at(i); - print_err_msg_type(note, color, ErrTypeNote); - } -} - -void print_err_msg(ErrorMsg *err, ErrColor color) { - print_err_msg_type(err, color, ErrTypeError); -} - -void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) { - parent->notes.append(note); -} - -ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, - Buf *msg) -{ - ErrorMsg *err_msg = heap::c_allocator.create(); - err_msg->path = path; - err_msg->msg = msg; - err_msg->line_start = 0; - err_msg->column_start = 0; - - if (source == nullptr) { - // Must initialize the buffer anyway - buf_init_from_str(&err_msg->line_buf, ""); - return err_msg; - } - - size_t line_start = 0; - size_t i = 0; - for (;i < byte_offset; i += 1) { - switch (source[i]) { - case '\n': - err_msg->line_start += 1; - err_msg->column_start = 0; - line_start = i + 1; - continue; - default: - err_msg->column_start += 1; - continue; - } - } - while (source[i] != '\n' && source[i] != 0) { - i += 1; - } - - buf_init_from_mem(&err_msg->line_buf, source + line_start, i - line_start); - - return err_msg; -} diff --git a/src/stage1/errmsg.hpp b/src/stage1/errmsg.hpp deleted file mode 100644 index b8b6b3e7f29a..000000000000 --- a/src/stage1/errmsg.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ERRMSG_HPP -#define ZIG_ERRMSG_HPP - -#include "buffer.hpp" -#include "list.hpp" -#include "stage1.h" - -struct ErrorMsg { - size_t line_start; - size_t column_start; - Buf *msg; - Buf *path; - Buf line_buf; - - ZigList notes; -}; - -void print_err_msg(ErrorMsg *msg, ErrColor color); - -void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note); -ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, Buf *msg); - -#endif diff --git a/src/stage1/error.cpp b/src/stage1/error.cpp deleted file mode 100644 index e77632e8f25d..000000000000 --- a/src/stage1/error.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "error.hpp" - -const char *err_str(Error err) { - switch (err) { - case ErrorNone: return "(no error)"; - case ErrorNoMem: return "out of memory"; - case ErrorInvalidFormat: return "invalid format"; - case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; - case ErrorAccess: return "access denied"; - case ErrorInterrupted: return "interrupted"; - case ErrorSystemResources: return "lack of system resources"; - case ErrorFileNotFound: return "file not found"; - case ErrorFileSystem: return "file system error"; - case ErrorFileTooBig: return "file too big"; - case ErrorDivByZero: return "division by zero"; - case ErrorOverflow: return "overflow"; - case ErrorPathAlreadyExists: return "path already exists"; - case ErrorUnexpected: return "unexpected error"; - case ErrorExactDivRemainder: return "exact division had a remainder"; - case ErrorNegativeDenominator: return "negative denominator"; - case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; - case ErrorCCompileErrors: return "C compile errors"; - case ErrorEndOfFile: return "end of file"; - case ErrorIsDir: return "is directory"; - case ErrorNotDir: return "not a directory"; - case ErrorUnsupportedOperatingSystem: return "unsupported operating system"; - case ErrorSharingViolation: return "sharing violation"; - case ErrorPipeBusy: return "pipe busy"; - case ErrorPrimitiveTypeNotFound: return "primitive type not found"; - case ErrorCacheUnavailable: return "cache unavailable"; - case ErrorPathTooLong: return "path too long"; - case ErrorCCompilerCannotFindFile: return "C compiler cannot find file"; - case ErrorReadingDepFile: return "failed to read .d file"; - case ErrorInvalidDepFile: return "invalid .d file"; - case ErrorMissingArchitecture: return "missing architecture"; - case ErrorMissingOperatingSystem: return "missing operating system"; - case ErrorUnknownArchitecture: return "unrecognized architecture"; - case ErrorUnknownOperatingSystem: return "unrecognized operating system"; - case ErrorUnknownABI: return "unrecognized C ABI"; - case ErrorInvalidFilename: return "invalid filename"; - case ErrorDiskQuota: return "disk space quota exceeded"; - case ErrorDiskSpace: return "out of disk space"; - case ErrorUnexpectedWriteFailure: return "unexpected write failure"; - case ErrorUnexpectedSeekFailure: return "unexpected seek failure"; - case ErrorUnexpectedFileTruncationFailure: return "unexpected file truncation failure"; - case ErrorUnimplemented: return "unimplemented"; - case ErrorOperationAborted: return "operation aborted"; - case ErrorBrokenPipe: return "broken pipe"; - case ErrorNoSpaceLeft: return "no space left"; - case ErrorNoCCompilerInstalled: return "no C compiler installed"; - case ErrorNotLazy: return "not lazy"; - case ErrorIsAsync: return "is async"; - case ErrorImportOutsidePkgPath: return "import of file outside package path"; - case ErrorUnknownCpu: return "unknown CPU"; - case ErrorUnknownCpuFeature: return "unknown CPU feature"; - case ErrorInvalidCpuFeatures: return "invalid CPU features"; - case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format"; - case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface"; - case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details"; - case ErrorBadPathName: return "bad path name"; - case ErrorSymLinkLoop: return "sym link loop"; - case ErrorProcessFdQuotaExceeded: return "process fd quota exceeded"; - case ErrorSystemFdQuotaExceeded: return "system fd quota exceeded"; - case ErrorNoDevice: return "no device"; - case ErrorDeviceBusy: return "device busy"; - case ErrorUnableToSpawnCCompiler: return "unable to spawn system C compiler"; - case ErrorCCompilerExitCode: return "system C compiler exited with failure code"; - case ErrorCCompilerCrashed: return "system C compiler crashed"; - case ErrorCCompilerCannotFindHeaders: return "system C compiler cannot find libc headers"; - case ErrorLibCRuntimeNotFound: return "libc runtime not found"; - case ErrorLibCStdLibHeaderNotFound: return "libc std lib headers not found"; - case ErrorLibCKernel32LibNotFound: return "kernel32 library not found"; - case ErrorUnsupportedArchitecture: return "unsupported architecture"; - case ErrorWindowsSdkNotFound: return "Windows SDK not found"; - case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path"; - case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker"; - case ErrorInvalidAbiVersion: return "invalid C ABI version"; - case ErrorInvalidOperatingSystemVersion: return "invalid operating system version"; - case ErrorUnknownClangOption: return "unknown Clang option"; - case ErrorNestedResponseFile: return "nested response file"; - case ErrorZigIsTheCCompiler: return "Zig was not provided with libc installation information, and so it does not know where the libc paths are on the system. Zig attempted to use the system C compiler to find out where the libc paths are, but discovered that Zig is being used as the system C compiler."; - case ErrorFileBusy: return "file is busy"; - case ErrorLocked: return "file is locked by another process"; - case ErrorInvalidCharacter: return "invalid character"; - case ErrorUnicodePointTooLarge: return "unicode codepoint too large"; - } - return "(invalid error)"; -} diff --git a/src/stage1/error.hpp b/src/stage1/error.hpp deleted file mode 100644 index 90772df10814..000000000000 --- a/src/stage1/error.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ERROR_HPP -#define ERROR_HPP - -#include "stage2.h" - -const char *err_str(Error err); - -#define assertNoError(err) assert((err) == ErrorNone); - -#endif diff --git a/src/stage1/hash_map.hpp b/src/stage1/hash_map.hpp deleted file mode 100644 index 0dad87289ebf..000000000000 --- a/src/stage1/hash_map.hpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_HASH_MAP_HPP -#define ZIG_HASH_MAP_HPP - -#include "util.hpp" - -#include - -template -struct MakePointer { - typedef K const *Type; - static Type convert(K const &val) { - return &val; - } -}; - -template -struct MakePointer { - typedef K *Type; - static Type convert(K * const &val) { - return val; - } -}; - -template -struct MakePointer { - typedef K const *Type; - static Type convert(K const * const &val) { - return val; - } -}; - -template::Type key), - bool (*EqualFn)(typename MakePointer::Type a, typename MakePointer::Type b)> -class HashMap { -public: - void init(int capacity) { - init_capacity(capacity); - } - void deinit(void) { - _entries.deinit(); - heap::c_allocator.deallocate(_index_bytes, - _indexes_len * capacity_index_size(_indexes_len)); - } - - struct Entry { - uint32_t hash; - uint32_t distance_from_start_index; - K key; - V value; - }; - - void clear() { - _entries.clear(); - memset(_index_bytes, 0, _indexes_len * capacity_index_size(_indexes_len)); - _max_distance_from_start_index = 0; - _modification_count += 1; - } - - size_t size() const { - return _entries.length; - } - - void put(const K &key, const V &value) { - _modification_count += 1; - - // This allows us to take a pointer to an entry in `internal_put` which - // will not become a dead pointer when the array list is appended. - _entries.ensure_capacity(_entries.length + 1); - - if (_index_bytes == nullptr) { - if (_entries.length < 16) { - _entries.append({HashFunction(MakePointer::convert(key)), 0, key, value}); - return; - } else { - _indexes_len = 32; - _index_bytes = heap::c_allocator.allocate(_indexes_len); - _max_distance_from_start_index = 0; - for (size_t i = 0; i < _entries.length; i += 1) { - Entry *entry = &_entries.items[i]; - put_index(entry, i, _index_bytes); - } - return internal_put(key, value, _index_bytes); - } - } - - // if we would get too full (60%), double the indexes size - if ((_entries.length + 1) * 5 >= _indexes_len * 3) { - heap::c_allocator.deallocate(_index_bytes, - _indexes_len * capacity_index_size(_indexes_len)); - _indexes_len *= 2; - size_t sz = capacity_index_size(_indexes_len); - // This zero initializes the bytes, setting them all empty. - _index_bytes = heap::c_allocator.allocate(_indexes_len * sz); - _max_distance_from_start_index = 0; - for (size_t i = 0; i < _entries.length; i += 1) { - Entry *entry = &_entries.items[i]; - switch (sz) { - case 1: - put_index(entry, i, (uint8_t*)_index_bytes); - continue; - case 2: - put_index(entry, i, (uint16_t*)_index_bytes); - continue; - case 4: - put_index(entry, i, (uint32_t*)_index_bytes); - continue; - default: - put_index(entry, i, (size_t*)_index_bytes); - continue; - } - } - } - - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_put(key, value, (uint8_t*)_index_bytes); - case 2: return internal_put(key, value, (uint16_t*)_index_bytes); - case 4: return internal_put(key, value, (uint32_t*)_index_bytes); - default: return internal_put(key, value, (size_t*)_index_bytes); - } - } - - Entry *put_unique(const K &key, const V &value) { - // TODO make this more efficient - Entry *entry = internal_get(key); - if (entry) - return entry; - put(key, value); - return nullptr; - } - - const V &get(const K &key) const { - Entry *entry = internal_get(key); - if (!entry) - zig_panic("key not found"); - return entry->value; - } - - Entry *maybe_get(const K &key) const { - return internal_get(key); - } - - bool remove(const K &key) { - bool deleted_something = maybe_remove(key); - if (!deleted_something) - zig_panic("key not found"); - return deleted_something; - } - - bool maybe_remove(const K &key) { - _modification_count += 1; - if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { - _entries.swap_remove(i); - return true; - } - } - return false; - } - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_remove(key, (uint8_t*)_index_bytes); - case 2: return internal_remove(key, (uint16_t*)_index_bytes); - case 4: return internal_remove(key, (uint32_t*)_index_bytes); - default: return internal_remove(key, (size_t*)_index_bytes); - } - } - - class Iterator { - public: - Entry *next() { - if (_inital_modification_count != _table->_modification_count) - zig_panic("concurrent modification"); - if (_index >= _table->_entries.length) - return nullptr; - Entry *entry = &_table->_entries.items[_index]; - _index += 1; - return entry; - } - private: - const HashMap * _table; - // iterator through the entry array - size_t _index = 0; - // used to detect concurrent modification - uint32_t _inital_modification_count; - Iterator(const HashMap * table) : - _table(table), _inital_modification_count(table->_modification_count) { - } - friend HashMap; - }; - - // you must not modify the underlying HashMap while this iterator is still in use - Iterator entry_iterator() const { - return Iterator(this); - } - -private: - // Maintains insertion order. - ZigList _entries; - // If _indexes_len is less than 2**8, this is an array of uint8_t. - // If _indexes_len is less than 2**16, it is an array of uint16_t. - // If _indexes_len is less than 2**32, it is an array of uint32_t. - // Otherwise it is size_t. - // It's off by 1. 0 means empty slot, 1 means index 0, etc. - uint8_t *_index_bytes; - // This is the number of indexes. When indexes are bytes, it equals number of bytes. - // When indexes are uint16_t, _indexes_len is half the number of bytes. - size_t _indexes_len; - - size_t _max_distance_from_start_index; - // This is used to detect bugs where a hashtable is edited while an iterator is running. - uint32_t _modification_count; - - void init_capacity(size_t capacity) { - _entries = {}; - _entries.ensure_capacity(capacity); - _indexes_len = 0; - if (capacity >= 16) { - // So that at capacity it will only be 60% full. - _indexes_len = capacity * 5 / 3; - size_t sz = capacity_index_size(_indexes_len); - // This zero initializes _index_bytes which sets them all to empty. - _index_bytes = heap::c_allocator.allocate(_indexes_len * sz); - } else { - _index_bytes = nullptr; - } - - _max_distance_from_start_index = 0; - _modification_count = 0; - } - - static size_t capacity_index_size(size_t len) { - if (len < UINT8_MAX) - return 1; - if (len < UINT16_MAX) - return 2; - if (len < UINT32_MAX) - return 4; - return sizeof(size_t); - } - - template - void internal_put(const K &key, const V &value, I *indexes) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - uint32_t distance_from_start_index = 0; - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over < _indexes_len; - roll_over += 1, distance_from_start_index += 1) - { - size_t index_index = (start_index + roll_over) % _indexes_len; - I index_data = indexes[index_index]; - if (index_data == 0) { - _entries.append_assuming_capacity({ hash, distance_from_start_index, key, value }); - indexes[index_index] = _entries.length; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - return; - } - // This pointer survives the following append because we call - // _entries.ensure_capacity before internal_put. - Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) { - *entry = {hash, distance_from_start_index, key, value}; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - return; - } - if (entry->distance_from_start_index < distance_from_start_index) { - // In this case, we did not find the item. We will put a new entry. - // However, we will use this index for the new entry, and move - // the previous index down the line, to keep the _max_distance_from_start_index - // as small as possible. - _entries.append_assuming_capacity({ hash, distance_from_start_index, key, value }); - indexes[index_index] = _entries.length; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - - distance_from_start_index = entry->distance_from_start_index; - - // Find somewhere to put the index we replaced by shifting - // following indexes backwards. - roll_over += 1; - distance_from_start_index += 1; - for (; roll_over < _indexes_len; roll_over += 1, distance_from_start_index += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - I next_index_data = indexes[index_index]; - if (next_index_data == 0) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - return; - } - Entry *next_entry = &_entries.items[next_index_data - 1]; - if (next_entry->distance_from_start_index < distance_from_start_index) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - distance_from_start_index = next_entry->distance_from_start_index; - entry = next_entry; - index_data = next_index_data; - } - } - zig_unreachable(); - } - } - zig_unreachable(); - } - - template - void put_index(Entry *entry, size_t entry_index, I *indexes) { - size_t start_index = hash_to_index(entry->hash); - size_t index_data = entry_index + 1; - for (size_t roll_over = 0, distance_from_start_index = 0; - roll_over < _indexes_len; roll_over += 1, distance_from_start_index += 1) - { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t next_index_data = indexes[index_index]; - if (next_index_data == 0) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - return; - } - Entry *next_entry = &_entries.items[next_index_data - 1]; - if (next_entry->distance_from_start_index < distance_from_start_index) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - distance_from_start_index = next_entry->distance_from_start_index; - entry = next_entry; - index_data = next_index_data; - } - } - zig_unreachable(); - } - - Entry *internal_get(const K &key) const { - if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { - return &_entries.items[i]; - } - } - return nullptr; - } - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_get2(key, (uint8_t*)_index_bytes); - case 2: return internal_get2(key, (uint16_t*)_index_bytes); - case 4: return internal_get2(key, (uint32_t*)_index_bytes); - default: return internal_get2(key, (size_t*)_index_bytes); - } - } - - template - Entry *internal_get2(const K &key, I *indexes) const { - uint32_t hash = HashFunction(MakePointer::convert(key)); - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t index_data = indexes[index_index]; - if (index_data == 0) - return nullptr; - - Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) - return entry; - } - return nullptr; - } - - size_t hash_to_index(uint32_t hash) const { - return ((size_t)hash) % _indexes_len; - } - - template - bool internal_remove(const K &key, I *indexes) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t index_data = indexes[index_index]; - if (index_data == 0) - return false; - - size_t index = index_data - 1; - Entry *entry = &_entries.items[index]; - if (entry->hash != hash || !EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) - continue; - - size_t prev_index = index_index; - _entries.swap_remove(index); - if (_entries.length > 0 && _entries.length != index) { - // Because of the swap remove, now we need to update the index that was - // pointing to the last entry and is now pointing to this removed item slot. - update_entry_index(_entries.length, index, indexes); - } - - // Now we have to shift over the following indexes. - roll_over += 1; - for (; roll_over < _indexes_len; roll_over += 1) { - size_t next_index = (start_index + roll_over) % _indexes_len; - if (indexes[next_index] == 0) { - indexes[prev_index] = 0; - return true; - } - Entry *next_entry = &_entries.items[indexes[next_index] - 1]; - if (next_entry->distance_from_start_index == 0) { - indexes[prev_index] = 0; - return true; - } - indexes[prev_index] = indexes[next_index]; - prev_index = next_index; - next_entry->distance_from_start_index -= 1; - } - zig_unreachable(); - } - return false; - } - - template - void update_entry_index(size_t old_entry_index, size_t new_entry_index, I *indexes) { - size_t start_index = hash_to_index(_entries.items[new_entry_index].hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - if (indexes[index_index] == old_entry_index + 1) { - indexes[index_index] = new_entry_index + 1; - return; - } - } - zig_unreachable(); - } -}; -#endif diff --git a/src/stage1/heap.cpp b/src/stage1/heap.cpp deleted file mode 100644 index caf15cde365e..000000000000 --- a/src/stage1/heap.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include -#include - -#include "heap.hpp" - -namespace heap { - -extern mem::Allocator &bootstrap_allocator; - -// -// BootstrapAllocator implementation is identical to CAllocator minus -// profile profile functionality. Splitting off to a base interface doesn't -// seem worthwhile. -// - -void BootstrapAllocator::init(const char *name) {} -void BootstrapAllocator::deinit() {} - -void *BootstrapAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *BootstrapAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *BootstrapAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *BootstrapAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void BootstrapAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -void CAllocator::init(const char *name) { } - -void CAllocator::deinit() { } - -CAllocator *CAllocator::construct(mem::Allocator *allocator, const char *name) { - auto p = new(allocator->create()) CAllocator(); - p->init(name); - return p; -} - -void CAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *CAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *CAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *CAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *CAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void CAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -struct ArenaAllocator::Impl { - Allocator *backing; - - // regular allocations bump through a segment of static size - struct Segment { - static constexpr size_t size = 65536; - static constexpr size_t object_threshold = 4096; - - uint8_t data[size]; - }; - - // active segment - Segment *segment; - size_t segment_offset; - - // keep track of segments - struct SegmentTrack { - static constexpr size_t size = (4096 - sizeof(SegmentTrack *)) / sizeof(Segment *); - - // null if first - SegmentTrack *prev; - Segment *segments[size]; - }; - static_assert(sizeof(SegmentTrack) <= 4096, "unwanted struct padding"); - - // active segment track - SegmentTrack *segment_track; - size_t segment_track_remain; - - // individual allocations punted to backing allocator - struct Object { - uint8_t *ptr; - size_t len; - }; - - // keep track of objects - struct ObjectTrack { - static constexpr size_t size = (4096 - sizeof(ObjectTrack *)) / sizeof(Object); - - // null if first - ObjectTrack *prev; - Object objects[size]; - }; - static_assert(sizeof(ObjectTrack) <= 4096, "unwanted struct padding"); - - // active object track - ObjectTrack *object_track; - size_t object_track_remain; - - ATTRIBUTE_RETURNS_NOALIAS inline void *allocate(const mem::TypeInfo& info, size_t count); - inline void *reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count); - - inline void new_segment(); - inline void track_segment(); - inline void track_object(Object object); -}; - -void *ArenaAllocator::Impl::allocate(const mem::TypeInfo& info, size_t count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 || count == 0) - return nullptr; -#endif - const size_t nbytes = info.size * count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (nbytes >= Segment::object_threshold) { - auto ptr = this->backing->allocate(nbytes); - this->track_object({ptr, nbytes}); - return ptr; - } - if (this->segment_offset + nbytes > Segment::size) - this->new_segment(); - auto ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += nbytes; - return ptr; -} - -void *ArenaAllocator::Impl::reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 && old_ptr == nullptr) - return nullptr; -#endif - const size_t new_nbytes = info.size * new_count; - if (new_nbytes <= info.size * old_count) - return old_ptr; - const size_t old_nbytes = info.size * old_count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (new_nbytes >= Segment::object_threshold) { - auto new_ptr = this->backing->allocate(new_nbytes); - this->track_object({new_ptr, new_nbytes}); - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; - } - if (this->segment_offset + new_nbytes > Segment::size) - this->new_segment(); - auto new_ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += new_nbytes; - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; -} - -void ArenaAllocator::Impl::new_segment() { - this->segment = this->backing->create(); - this->segment_offset = 0; - this->track_segment(); -} - -void ArenaAllocator::Impl::track_segment() { - assert(this->segment != nullptr); - if (this->segment_track_remain < 1) { - auto prev = this->segment_track; - this->segment_track = this->backing->create(); - this->segment_track->prev = prev; - this->segment_track_remain = SegmentTrack::size; - } - this->segment_track_remain -= 1; - this->segment_track->segments[this->segment_track_remain] = this->segment; -} - -void ArenaAllocator::Impl::track_object(Object object) { - if (this->object_track_remain < 1) { - auto prev = this->object_track; - this->object_track = this->backing->create(); - this->object_track->prev = prev; - this->object_track_remain = ObjectTrack::size; - } - this->object_track_remain -= 1; - this->object_track->objects[this->object_track_remain] = object; -} - -void ArenaAllocator::init(Allocator *backing, const char *name) { - this->impl = bootstrap_allocator.create(); - { - auto &r = *this->impl; - r.backing = backing; - r.segment_offset = Impl::Segment::size; - } -} - -void ArenaAllocator::deinit() { - auto &backing = *this->impl->backing; - - // segments - if (this->impl->segment_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->segment_track->prev; - { - auto t = this->impl->segment_track; - for (size_t i = this->impl->segment_track_remain; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - prev = t->prev; - backing.destroy(t); - t = prev; - } - } - - // objects - if (this->impl->object_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->object_track->prev; - { - auto t = this->impl->object_track; - for (size_t i = this->impl->object_track_remain; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - prev = t->prev; - backing.destroy(t); - t = prev; - } - } -} - -ArenaAllocator *ArenaAllocator::construct(mem::Allocator *allocator, mem::Allocator *backing, const char *name) { - auto p = new(allocator->create()) ArenaAllocator; - p->init(backing, name); - return p; -} - -void ArenaAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *ArenaAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); -} - -void *ArenaAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->impl->reallocate(info, old_ptr, old_count, new_count); -} - -void ArenaAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - // noop -} - -BootstrapAllocator bootstrap_allocator_state; -mem::Allocator &bootstrap_allocator = bootstrap_allocator_state; - -CAllocator c_allocator_state; -mem::Allocator &c_allocator = c_allocator_state; - -} // namespace heap diff --git a/src/stage1/heap.hpp b/src/stage1/heap.hpp deleted file mode 100644 index a9467bc8318d..000000000000 --- a/src/stage1/heap.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_HEAP_HPP -#define ZIG_HEAP_HPP - -#include "util_base.hpp" -#include "mem.hpp" - -namespace heap { - -struct BootstrapAllocator final : mem::Allocator { - void init(const char *name); - void deinit(); - void destruct(Allocator *allocator) {} - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; -}; - -struct CAllocator final : mem::Allocator { - void init(const char *name); - void deinit(); - - static CAllocator *construct(mem::Allocator *allocator, const char *name); - void destruct(mem::Allocator *allocator) final; - - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; - -}; - -// -// arena allocator -// -// - allocations are backed by the underlying allocator's memory -// - allocations are N:1 relationship to underlying allocations -// - dellocations are noops -// - deinit() releases all underlying memory -// -struct ArenaAllocator final : mem::Allocator { - void init(Allocator *backing, const char *name); - void deinit(); - - static ArenaAllocator *construct(mem::Allocator *allocator, mem::Allocator *backing, const char *name); - void destruct(mem::Allocator *allocator) final; - - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; - - struct Impl; - Impl *impl; -}; - -extern BootstrapAllocator bootstrap_allocator_state; -extern mem::Allocator &bootstrap_allocator; - -extern CAllocator c_allocator_state; -extern mem::Allocator &c_allocator; - -} // namespace heap - -#endif diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp deleted file mode 100644 index e15ca2c0298f..000000000000 --- a/src/stage1/ir.cpp +++ /dev/null @@ -1,26627 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "astgen.hpp" -#include "analyze.hpp" -#include "error.hpp" -#include "ir.hpp" -#include "ir_print.hpp" -#include "os.hpp" -#include "range_set.hpp" -#include "softfloat.hpp" -#include "softfloat_ext.hpp" -#include "util.hpp" -#include "mem_list.hpp" -#include "all_types.hpp" -#include "zigendian.h" - -#include -#include - -struct IrBuilderGen { - CodeGen *codegen; - Stage1Air *exec; - Stage1AirBasicBlock *current_basic_block; - - // track for immediate post-analysis destruction - mem::List constants; -}; - -struct IrAnalyze { - CodeGen *codegen; - Stage1Zir *zir; - Stage1ZirBasicBlock *zir_current_basic_block; - IrBuilderGen new_irb; - size_t old_bb_index; - size_t instruction_index; - ZigType *explicit_return_type; - AstNode *explicit_return_type_source_node; - ZigList src_implicit_return_type_list; - ZigList resume_stack; - Stage1ZirBasicBlock *const_predecessor_bb; - size_t ref_count; - size_t break_debug_id; // for debugging purposes - Stage1AirInst *return_ptr; - Stage1Air *parent_exec; - size_t *backward_branch_count; - size_t *backward_branch_quota; - ZigFn *fn; - Stage1ZirInst *suspend_source_instr; - - // For the purpose of using in a debugger - void dump(); -}; - -enum ConstCastResultId { - ConstCastResultIdOk, - ConstCastResultIdInvalid, - ConstCastResultIdErrSet, - ConstCastResultIdErrSetGlobal, - ConstCastResultIdPointerChild, - ConstCastResultIdSliceChild, - ConstCastResultIdOptionalChild, - ConstCastResultIdOptionalShape, - ConstCastResultIdErrorUnionPayload, - ConstCastResultIdErrorUnionErrorSet, - ConstCastResultIdFnAlign, - ConstCastResultIdFnCC, - ConstCastResultIdFnVarArgs, - ConstCastResultIdFnIsGeneric, - ConstCastResultIdFnReturnType, - ConstCastResultIdFnArgCount, - ConstCastResultIdFnGenericArgCount, - ConstCastResultIdFnArg, - ConstCastResultIdFnArgNoAlias, - ConstCastResultIdType, - ConstCastResultIdUnresolvedInferredErrSet, - ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdBadAllowsZero, - ConstCastResultIdArrayChild, - ConstCastResultIdSentinelArrays, - ConstCastResultIdPtrLens, - ConstCastResultIdCV, - ConstCastResultIdPtrSentinel, - ConstCastResultIdIntShorten, - ConstCastResultIdVectorLength, - ConstCastResultIdVectorChild, -}; - -struct ConstCastOnly; -struct ConstCastArg { - size_t arg_index; - ZigType *actual_param_type; - ZigType *expected_param_type; - ConstCastOnly *child; -}; - -struct ConstCastArgNoAlias { - size_t arg_index; -}; - -struct ConstCastOptionalMismatch; -struct ConstCastPointerMismatch; -struct ConstCastSliceMismatch; -struct ConstCastErrUnionErrSetMismatch; -struct ConstCastErrUnionPayloadMismatch; -struct ConstCastErrSetMismatch; -struct ConstCastTypeMismatch; -struct ConstCastArrayMismatch; -struct ConstCastBadAllowsZero; -struct ConstCastBadNullTermArrays; -struct ConstCastBadCV; -struct ConstCastPtrSentinel; -struct ConstCastIntShorten; - -struct ConstCastOnly { - ConstCastResultId id; - union { - ConstCastErrSetMismatch *error_set_mismatch; - ConstCastPointerMismatch *pointer_mismatch; - ConstCastSliceMismatch *slice_mismatch; - ConstCastOptionalMismatch *optional; - ConstCastErrUnionPayloadMismatch *error_union_payload; - ConstCastErrUnionErrSetMismatch *error_union_error_set; - ConstCastTypeMismatch *type_mismatch; - ConstCastArrayMismatch *array_mismatch; - ConstCastOnly *return_type; - ConstCastOnly *null_wrap_ptr_child; - ConstCastArg fn_arg; - ConstCastArgNoAlias arg_no_alias; - ConstCastBadAllowsZero *bad_allows_zero; - ConstCastBadNullTermArrays *sentinel_arrays; - ConstCastBadCV *bad_cv; - ConstCastPtrSentinel *bad_ptr_sentinel; - ConstCastIntShorten *int_shorten; - } data; -}; - -struct ConstCastTypeMismatch { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastOptionalMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastPointerMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastSliceMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastArrayMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastErrUnionErrSetMismatch { - ConstCastOnly child; - ZigType *wanted_err_set; - ZigType *actual_err_set; -}; - -struct ConstCastErrUnionPayloadMismatch { - ConstCastOnly child; - ZigType *wanted_payload; - ZigType *actual_payload; -}; - -struct ConstCastErrSetMismatch { - ZigList missing_errors; -}; - -struct ConstCastBadAllowsZero { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastBadNullTermArrays { - ConstCastOnly child; - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastBadCV { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastPtrSentinel { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastIntShorten { - ZigType *wanted_type; - ZigType *actual_type; -}; - -// for debugging purposes -struct DbgIrBreakPoint { - const char *src_file; - uint32_t line; -}; - -static Stage1AirInst *ir_implicit_cast(IrAnalyze *ira, Stage1AirInst *value, ZigType *expected_type); -static Stage1AirInst *ir_implicit_cast2(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *expected_type); -static Stage1AirInst *ir_get_deref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, - ResultLoc *result_loc); -static Stage1AirInst *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, AstNode *container_ptr_src, - ZigType *container_type, bool initializing); -static Stage1AirInst *ir_get_var_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var); -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, Stage1AirInst *op); -static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); -static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const); -static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val); -static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val); -static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *out_val, ZigValue *ptr_val); -static Stage1AirInst *ir_analyze_ptr_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AstNode *ptr_src, ZigType *dest_type, AstNode *dest_type_src, - bool safety_check_on, bool keep_bigger_alignment); -static ZigValue *ir_resolve_const(IrAnalyze *ira, Stage1AirInst *value, UndefAllowed undef_allowed); -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); -static Stage1AirInst *ir_analyze_int_to_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *ptr_type); -static Stage1AirInst *ir_analyze_bit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *dest_type); -static Stage1AirInst *ir_resolve_result_raw(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, bool allow_discard); -static Stage1AirInst *ir_resolve_result(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, bool allow_discard); -static Stage1AirInst *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing); -static Stage1AirInst *ir_analyze_unwrap_error_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing); -static Stage1AirInst *ir_analyze_unwrap_err_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool initializing); -static Stage1AirInst *ir_analyze_store_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *uncasted_value, bool allow_write_through_const); -static void ir_reset_result(ResultLoc *result_loc); -static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - TypeStructField *field, Stage1AirInst *struct_ptr, ZigType *struct_type, bool initializing); -static Stage1AirInst *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, ZigType *container_type); -static Stage1AirInst *ir_analyze_test_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value); -static Stage1AirInst *ir_error_dependency_loop(IrAnalyze *ira, AstNode *source_node); -static Stage1AirInst *ir_const_undef(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty); -static Stage1AirInst *ir_analyze_union_init(IrAnalyze *ira, Scope *scope, AstNode *source_node, - AstNode *field_source_node, ZigType *union_type, Buf *field_name, Stage1AirInst *field_result_loc, - Stage1AirInst *result_loc); -static Stage1AirInst *ir_analyze_struct_value_field_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_operand, TypeStructField *field); -static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right); -static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right); -static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field); -static void value_to_bigfloat(BigFloat *out, ZigValue *val); - -static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val); -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len); - - -static void ir_assert_impl(bool ok, Stage1AirInst *source_instruction, char const *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - -void destroy_instruction_gen(Stage1AirInst *inst) { - switch (inst->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdReturn: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBinOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCall: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCondBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPhi: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnreachable: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdElemPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVarPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReturnPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdLoadPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdStorePtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorStoreElem: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdStructFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnionFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAsm: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTestNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOptionalUnwrapPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPopCount: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdClz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCtz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBswap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBitReverse: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSwitchBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnionTag: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCmpxchg: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFence: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReduce: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTruncate: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdShuffleVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSelect: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSplat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBoolNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMemset: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMemcpy: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBreakpoint: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReturnAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameHandle: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameSize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOverflowOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTestErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnwrapErrCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnwrapErrPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOptionalWrap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrWrapCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrWrapPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWidenOrShorten: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToEnum: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTagName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPanic: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFieldParentPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAlignCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrorReturnTrace: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicRmw: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSaveErrRetAddr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFloatOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMulAdd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicLoad: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicStore: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdDeclVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdArrayToVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorToArray: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrOfArrayToSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAssertZero: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAssertNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAlloca: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSuspendBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSuspendFinish: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdResume: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAwait: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSpillBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSpillEnd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorExtractElem: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBinaryNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdNegation: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWasmMemorySize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWasmMemoryGrow: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdExtern: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPrefetch: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - } - zig_unreachable(); -} - -static void ira_ref(IrAnalyze *ira) { - ira->ref_count += 1; -} -static void ira_deref(IrAnalyze *ira) { - if (ira->ref_count > 1) { - ira->ref_count -= 1; - - // immediate destruction of dangling Stage1AirInstConst is not possible - // free tracking memory because it will never be used - ira->new_irb.constants.deinit(&heap::c_allocator); - return; - } - assert(ira->ref_count != 0); - - for (size_t bb_i = 0; bb_i < ira->zir->basic_block_list.length; bb_i += 1) { - Stage1ZirBasicBlock *pass1_bb = ira->zir->basic_block_list.items[bb_i]; - for (size_t inst_i = 0; inst_i < pass1_bb->instruction_list.length; inst_i += 1) { - Stage1ZirInst *pass1_inst = pass1_bb->instruction_list.items[inst_i]; - destroy_instruction_src(pass1_inst); - } - heap::c_allocator.destroy(pass1_bb); - } - ira->zir->basic_block_list.deinit(); - ira->zir->tld_list.deinit(); - heap::c_allocator.destroy(ira->zir); - ira->src_implicit_return_type_list.deinit(); - ira->resume_stack.deinit(); - - // destroy dangling Stage1AirInstConst - for (size_t i = 0; i < ira->new_irb.constants.length; i += 1) { - auto constant = ira->new_irb.constants.items[i]; - if (constant->base.ref_count == 0 && !ir_inst_gen_has_side_effects(&constant->base)) - destroy_instruction_gen(&constant->base); - } - ira->new_irb.constants.deinit(&heap::c_allocator); - - heap::c_allocator.destroy(ira); -} - -static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_val) { - assert(get_src_ptr_type(const_val->type) != nullptr); - assert(const_val->special == ConstValSpecialStatic); - - switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) { - case OnePossibleValueInvalid: - return nullptr; - case OnePossibleValueYes: - return get_the_one_possible_value(g, const_val->type->data.pointer.child_type); - case OnePossibleValueNo: - break; - } - - ZigValue *result; - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - result = const_val->data.x_ptr.data.ref.pointee; - break; - case ConstPtrSpecialBaseArray: { - ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - if (elem_index == array_val->type->data.array.len) { - result = array_val->type->data.array.sentinel; - } else { - expand_undef_array(g, array_val); - result = &array_val->data.x_array.data.s_none.elements[elem_index]; - } - break; - } - case ConstPtrSpecialSubArray: { - ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - - expand_undef_array(g, array_val); - result = g->pass1_arena->create(); - result->special = array_val->special; - result->type = get_array_type(g, array_val->type->data.array.child_type, - array_val->type->data.array.len - elem_index, array_val->type->data.array.sentinel); - result->data.x_array.special = ConstArraySpecialNone; - result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; - result->parent.id = ConstParentIdArray; - result->parent.data.p_array.array_val = array_val; - result->parent.data.p_array.elem_index = elem_index; - break; - } - case ConstPtrSpecialBaseStruct: { - ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; - expand_undef_struct(g, struct_val); - size_t field_index = const_val->data.x_ptr.data.base_struct.field_index; - assert(struct_val->type->id == ZigTypeIdStruct); - assert(!struct_val->type->data.structure.fields[field_index]->is_comptime); - result = struct_val->data.x_struct.fields[field_index]; - break; - } - case ConstPtrSpecialBaseErrorUnionCode: - result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set; - break; - case ConstPtrSpecialBaseErrorUnionPayload: - result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload; - break; - case ConstPtrSpecialBaseOptionalPayload: - result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional; - break; - case ConstPtrSpecialNull: - result = const_val; - break; - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_unreachable(); - } - assert(result != nullptr); - return result; -} - -static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { - assert(get_src_ptr_type(const_val->type) != nullptr); - assert(const_val->special == ConstValSpecialStatic); - - InferredStructField *isf = const_val->type->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - assert(field->init_val != nullptr); - return field->init_val; - } - ZigValue *struct_val = const_ptr_pointee_unchecked_no_isf(g, const_val); - assert(struct_val->type->id == ZigTypeIdStruct); - return struct_val->data.x_struct.fields[field->src_index]; - } - - return const_ptr_pointee_unchecked_no_isf(g, const_val); -} - -static bool is_tuple(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialInferredTuple; -} - -static bool is_slice(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; -} - -// This function returns true when you can change the type of a ZigValue and the -// value remains meaningful. -static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { - if (expected == actual) - return true; - - if (get_src_ptr_type(expected) != nullptr && get_src_ptr_type(actual) != nullptr) - return true; - - if (is_opt_err_set(expected) && is_opt_err_set(actual)) - return true; - - // XXX: Vectors and arrays are interchangeable at comptime - if (expected->id != actual->id) - return false; - - switch (expected->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdErrorSet: - case ZigTypeIdOpaque: - case ZigTypeIdAnyFrame: - case ZigTypeIdFn: - return true; - case ZigTypeIdPointer: - return expected->data.pointer.inferred_struct_field == actual->data.pointer.inferred_struct_field; - case ZigTypeIdFloat: - return expected->data.floating.bit_count == actual->data.floating.bit_count; - case ZigTypeIdInt: - return expected->data.integral.is_signed == actual->data.integral.is_signed; - case ZigTypeIdStruct: - return is_slice(expected) && is_slice(actual); - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFnFrame: - return false; - case ZigTypeIdVector: - return expected->data.vector.len == actual->data.vector.len && - types_have_same_zig_comptime_repr(codegen, expected->data.vector.elem_type, actual->data.vector.elem_type); - case ZigTypeIdArray: - return expected->data.array.len == actual->data.array.len && - expected->data.array.child_type == actual->data.array.child_type && - (expected->data.array.sentinel == nullptr || (actual->data.array.sentinel != nullptr && - const_values_equal(codegen, expected->data.array.sentinel, actual->data.array.sentinel))); - } - zig_unreachable(); -} - -static void ir_inst_gen_append(Stage1AirBasicBlock *basic_block, Stage1AirInst *instruction) { - assert(basic_block); - assert(instruction); - basic_block->instruction_list.append(instruction); -} - -static size_t exec_next_debug_id_gen(Stage1Air *exec) { - size_t result = exec->next_debug_id; - exec->next_debug_id += 1; - return result; -} - -static bool value_is_comptime(ZigValue *const_val) { - return const_val->special != ConstValSpecialRuntime; -} - -static bool instr_is_comptime(Stage1AirInst *instruction) { - return value_is_comptime(instruction->value); -} - -static void ir_ref_inst_gen(Stage1AirInst *instruction) { - assert(instruction->id != Stage1AirInstIdInvalid); - instruction->ref_count += 1; -} - -static void create_result_ptr(CodeGen *codegen, ZigType *expected_type, - ZigValue **out_result, ZigValue **out_result_ptr) -{ - ZigValue *result = codegen->pass1_arena->create(); - ZigValue *result_ptr = codegen->pass1_arena->create(); - result->special = ConstValSpecialUndef; - result->type = expected_type; - result_ptr->special = ConstValSpecialStatic; - result_ptr->type = get_pointer_to_type(codegen, result->type, false); - result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar; - result_ptr->data.x_ptr.special = ConstPtrSpecialRef; - result_ptr->data.x_ptr.data.ref.pointee = result; - - *out_result = result; - *out_result_ptr = result_ptr; -} - -ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { - Error err; - - ZigValue *result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, ira->codegen->builtin_types.entry_type, &result, &result_ptr); - - if ((err = ir_eval_const_value(ira->codegen, scope, node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - nullptr, nullptr, node, nullptr, ira->new_irb.exec, nullptr, UndefBad))) - { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_invalid(result->type)) - return ira->codegen->builtin_types.entry_invalid; - - assert(result->special != ConstValSpecialRuntime); - ZigType *res_type = result->data.x_type; - - return res_type; -} - -static Stage1AirBasicBlock *ir_create_basic_block_gen(IrAnalyze *ira, Scope *scope, const char *name_hint) { - Stage1AirBasicBlock *result = heap::c_allocator.create(); - result->scope = scope; - result->name_hint = name_hint; - result->debug_id = exec_next_debug_id_gen(ira->new_irb.exec); - return result; -} - -static Stage1AirBasicBlock *ir_build_bb_from(IrAnalyze *ira, Stage1ZirBasicBlock *other_bb) { - Stage1AirBasicBlock *new_bb = ir_create_basic_block_gen(ira, other_bb->scope, other_bb->name_hint); - other_bb->child = new_bb; - return new_bb; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstDeclVar *) { - return Stage1AirInstIdDeclVar; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBr *) { - return Stage1AirInstIdBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCondBr *) { - return Stage1AirInstIdCondBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSwitchBr *) { - return Stage1AirInstIdSwitchBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPhi *) { - return Stage1AirInstIdPhi; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBinaryNot *) { - return Stage1AirInstIdBinaryNot; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstNegation *) { - return Stage1AirInstIdNegation; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBinOp *) { - return Stage1AirInstIdBinOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstLoadPtr *) { - return Stage1AirInstIdLoadPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstStorePtr *) { - return Stage1AirInstIdStorePtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorStoreElem *) { - return Stage1AirInstIdVectorStoreElem; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstStructFieldPtr *) { - return Stage1AirInstIdStructFieldPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnionFieldPtr *) { - return Stage1AirInstIdUnionFieldPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstElemPtr *) { - return Stage1AirInstIdElemPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVarPtr *) { - return Stage1AirInstIdVarPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturnPtr *) { - return Stage1AirInstIdReturnPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCall *) { - return Stage1AirInstIdCall; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturn *) { - return Stage1AirInstIdReturn; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCast *) { - return Stage1AirInstIdCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnreachable *) { - return Stage1AirInstIdUnreachable; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAsm *) { - return Stage1AirInstIdAsm; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTestNonNull *) { - return Stage1AirInstIdTestNonNull; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOptionalUnwrapPtr *) { - return Stage1AirInstIdOptionalUnwrapPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOptionalWrap *) { - return Stage1AirInstIdOptionalWrap; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnionTag *) { - return Stage1AirInstIdUnionTag; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstClz *) { - return Stage1AirInstIdClz; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCtz *) { - return Stage1AirInstIdCtz; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPopCount *) { - return Stage1AirInstIdPopCount; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBswap *) { - return Stage1AirInstIdBswap; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBitReverse *) { - return Stage1AirInstIdBitReverse; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstRef *) { - return Stage1AirInstIdRef; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrName *) { - return Stage1AirInstIdErrName; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCmpxchg *) { - return Stage1AirInstIdCmpxchg; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFence *) { - return Stage1AirInstIdFence; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReduce *) { - return Stage1AirInstIdReduce; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTruncate *) { - return Stage1AirInstIdTruncate; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstShuffleVector *) { - return Stage1AirInstIdShuffleVector; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSelect *) { - return Stage1AirInstIdSelect; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSplat *) { - return Stage1AirInstIdSplat; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBoolNot *) { - return Stage1AirInstIdBoolNot; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMemset *) { - return Stage1AirInstIdMemset; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMemcpy *) { - return Stage1AirInstIdMemcpy; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSlice *) { - return Stage1AirInstIdSlice; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBreakpoint *) { - return Stage1AirInstIdBreakpoint; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturnAddress *) { - return Stage1AirInstIdReturnAddress; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameAddress *) { - return Stage1AirInstIdFrameAddress; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameHandle *) { - return Stage1AirInstIdFrameHandle; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameSize *) { - return Stage1AirInstIdFrameSize; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOverflowOp *) { - return Stage1AirInstIdOverflowOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTestErr *) { - return Stage1AirInstIdTestErr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMulAdd *) { - return Stage1AirInstIdMulAdd; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFloatOp *) { - return Stage1AirInstIdFloatOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnwrapErrCode *) { - return Stage1AirInstIdUnwrapErrCode; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnwrapErrPayload *) { - return Stage1AirInstIdUnwrapErrPayload; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrWrapCode *) { - return Stage1AirInstIdErrWrapCode; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrWrapPayload *) { - return Stage1AirInstIdErrWrapPayload; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrCast *) { - return Stage1AirInstIdPtrCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBitCast *) { - return Stage1AirInstIdBitCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWidenOrShorten *) { - return Stage1AirInstIdWidenOrShorten; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToPtr *) { - return Stage1AirInstIdIntToPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrToInt *) { - return Stage1AirInstIdPtrToInt; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToEnum *) { - return Stage1AirInstIdIntToEnum; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToErr *) { - return Stage1AirInstIdIntToErr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrToInt *) { - return Stage1AirInstIdErrToInt; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPanic *) { - return Stage1AirInstIdPanic; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTagName *) { - return Stage1AirInstIdTagName; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFieldParentPtr *) { - return Stage1AirInstIdFieldParentPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAlignCast *) { - return Stage1AirInstIdAlignCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrorReturnTrace *) { - return Stage1AirInstIdErrorReturnTrace; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicRmw *) { - return Stage1AirInstIdAtomicRmw; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicLoad *) { - return Stage1AirInstIdAtomicLoad; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicStore *) { - return Stage1AirInstIdAtomicStore; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSaveErrRetAddr *) { - return Stage1AirInstIdSaveErrRetAddr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorToArray *) { - return Stage1AirInstIdVectorToArray; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstArrayToVector *) { - return Stage1AirInstIdArrayToVector; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAssertZero *) { - return Stage1AirInstIdAssertZero; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAssertNonNull *) { - return Stage1AirInstIdAssertNonNull; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrOfArrayToSlice *) { - return Stage1AirInstIdPtrOfArrayToSlice; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSuspendBegin *) { - return Stage1AirInstIdSuspendBegin; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSuspendFinish *) { - return Stage1AirInstIdSuspendFinish; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAwait *) { - return Stage1AirInstIdAwait; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstResume *) { - return Stage1AirInstIdResume; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSpillBegin *) { - return Stage1AirInstIdSpillBegin; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSpillEnd *) { - return Stage1AirInstIdSpillEnd; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorExtractElem *) { - return Stage1AirInstIdVectorExtractElem; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAlloca *) { - return Stage1AirInstIdAlloca; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstConst *) { - return Stage1AirInstIdConst; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWasmMemorySize *) { - return Stage1AirInstIdWasmMemorySize; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWasmMemoryGrow *) { - return Stage1AirInstIdWasmMemoryGrow; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) { - return Stage1AirInstIdExtern; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) { - return Stage1AirInstIdPrefetch; -} - -template -static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = exec_next_debug_id_gen(irb->exec); - special_instruction->base.value = irb->codegen->pass1_arena->create(); - return special_instruction; -} - -template -static T *ir_create_inst_noval(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = exec_next_debug_id_gen(irb->exec); - return special_instruction; -} - -template -static T *ir_build_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_gen(irb, scope, source_node); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -template -static T *ir_build_inst_noreturn(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_noval(irb, scope, source_node); - special_instruction->base.value = irb->codegen->intern.for_unreachable(); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -template -static T *ir_build_inst_void(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_noval(irb, scope, source_node); - special_instruction->base.value = irb->codegen->intern.for_void(); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -Stage1AirInst *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, - ZigType *var_type, const char *name_hint) -{ - Stage1AirInstAlloca *alloca_gen = heap::c_allocator.create(); - alloca_gen->base.id = Stage1AirInstIdAlloca; - alloca_gen->base.source_node = source_node; - alloca_gen->base.scope = scope; - alloca_gen->base.value = g->pass1_arena->create(); - alloca_gen->base.value->type = get_pointer_to_type(g, var_type, false); - alloca_gen->base.ref_count = 1; - alloca_gen->name_hint = name_hint; - fn->alloca_gen_list.append(alloca_gen); - return &alloca_gen->base; -} - -static Stage1AirInst *ir_build_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, Stage1AirInst *value, CastOp cast_op) -{ - Stage1AirInstCast *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = dest_type; - inst->value = value; - inst->cast_op = cast_op; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_cond_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *condition, - Stage1AirBasicBlock *then_block, Stage1AirBasicBlock *else_block) -{ - Stage1AirInstCondBr *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->condition = condition; - inst->then_block = then_block; - inst->else_block = else_block; - - ir_ref_inst_gen(condition); - - return &inst->base; -} - -static Stage1AirInst *ir_build_return_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand) { - Stage1AirInstReturn *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->operand = operand; - - if (operand != nullptr) ir_ref_inst_gen(operand); - - return &inst->base; -} - -static Stage1AirInst *ir_build_bin_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *res_type, - IrBinOp op_id, Stage1AirInst *op1, Stage1AirInst *op2, bool safety_check_on) -{ - Stage1AirInstBinOp *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = res_type; - inst->op_id = op_id; - inst->op1 = op1; - inst->op2 = op2; - inst->safety_check_on = safety_check_on; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - - return &inst->base; -} - - -static Stage1AirInst *ir_build_var_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var) { - Stage1AirInstVarPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->var = var; - - var->ref_count += 1; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_return_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstReturnPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - return &instruction->base; -} - -static Stage1AirInst *ir_build_elem_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array_ptr, Stage1AirInst *elem_index, bool safety_check_on, ZigType *return_type) -{ - Stage1AirInstElemPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = return_type; - instruction->array_ptr = array_ptr; - instruction->elem_index = elem_index; - instruction->safety_check_on = safety_check_on; - - ir_ref_inst_gen(array_ptr); - ir_ref_inst_gen(elem_index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, TypeStructField *field, ZigType *ptr_type) -{ - Stage1AirInstStructFieldPtr *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ptr_type; - inst->struct_ptr = struct_ptr; - inst->field = field; - - ir_ref_inst_gen(struct_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_union_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing, ZigType *ptr_type) -{ - Stage1AirInstUnionFieldPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = ptr_type; - inst->initializing = initializing; - inst->safety_check_on = safety_check_on; - inst->union_ptr = union_ptr; - inst->field = field; - - ir_ref_inst_gen(union_ptr); - - return &inst->base; -} - -static Stage1AirInstCall *ir_build_call_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1AirInst *fn_ref, size_t arg_count, Stage1AirInst **args, - CallModifier modifier, Stage1AirInst *new_stack, bool is_async_call_builtin, - Stage1AirInst *result_loc, ZigType *return_type) -{ - Stage1AirInstCall *call_instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - call_instruction->base.value->type = return_type; - call_instruction->fn_entry = fn_entry; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->arg_count = arg_count; - call_instruction->modifier = modifier; - call_instruction->is_async_call_builtin = is_async_call_builtin; - call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; - - if (fn_ref != nullptr) ir_ref_inst_gen(fn_ref); - for (size_t i = 0; i < arg_count; i += 1) - ir_ref_inst_gen(args[i]); - if (new_stack != nullptr) ir_ref_inst_gen(new_stack); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return call_instruction; -} - -static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool merge_comptime, - size_t incoming_count, Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type) -{ - assert(incoming_count != 0); - assert(incoming_count != SIZE_MAX); - - if (merge_comptime && instr_is_comptime(incoming_values[incoming_count - 1])) { - // We need to check whether all the merged values are comptime-known and equal. - // If so, we elide the runtime phi and replace it with any of the identical comptime-known values. - ZigValue *comptime_value = ir_resolve_const(ira, incoming_values[incoming_count - 1], UndefOk); - if (comptime_value == nullptr) - return ira->codegen->invalid_inst_gen; - - for (size_t i = incoming_count - 1; i > 0;) { - i -= 1; - if (!instr_is_comptime(incoming_values[i])) { - comptime_value = nullptr; - break; - } - ZigValue *value = ir_resolve_const(ira, incoming_values[i], UndefOk); - if (value == nullptr) - return ira->codegen->invalid_inst_gen; - if (!const_values_equal(ira->codegen, comptime_value, value)) { - comptime_value = nullptr; - break; - } - } - if (comptime_value != nullptr) - return incoming_values[0]; - } - - Stage1AirInstPhi *phi_instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - phi_instruction->base.value->type = result_type; - phi_instruction->incoming_count = incoming_count; - phi_instruction->incoming_blocks = incoming_blocks; - phi_instruction->incoming_values = incoming_values; - - for (size_t i = 0; i < incoming_count; i += 1) { - ir_ref_inst_gen(incoming_values[i]); - } - - return &phi_instruction->base; -} - -static Stage1AirInst *ir_build_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirBasicBlock *dest_block) { - Stage1AirInstBr *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->dest_block = dest_block; - - return &inst->base; -} - -static Stage1AirInst *ir_build_negation(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, ZigType *expr_type, bool wrapping) { - Stage1AirInstNegation *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->operand = operand; - instruction->wrapping = wrapping; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_binary_not(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - ZigType *expr_type) -{ - Stage1AirInstBinaryNot *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->operand = operand; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_unreachable_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstUnreachable *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_store_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, Stage1AirInst *value) { - Stage1AirInstStorePtr *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_vector_store_elem(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector_ptr, Stage1AirInst *index, Stage1AirInst *value) -{ - Stage1AirInstVectorStoreElem *inst = ir_build_inst_void( - &ira->new_irb, scope, source_node); - inst->vector_ptr = vector_ptr; - inst->index = index; - inst->value = value; - - ir_ref_inst_gen(vector_ptr); - ir_ref_inst_gen(index); - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_var_decl_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1AirInst *var_ptr) -{ - Stage1AirInstDeclVar *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->special = ConstValSpecialStatic; - inst->base.value->type = ira->codegen->builtin_types.entry_void; - inst->var = var; - inst->var_ptr = var_ptr; - - ir_ref_inst_gen(var_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_extern_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Buf *name, - GlobalLinkageId linkage, bool is_thread_local, ZigType *expr_type) -{ - Stage1AirInstExtern *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->name = name; - instruction->linkage = linkage; - instruction->is_thread_local = is_thread_local; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_load_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, ZigType *ty, Stage1AirInst *result_loc) -{ - Stage1AirInstLoadPtr *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - instruction->ptr = ptr; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(ptr); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Buf *asm_template, AsmToken *token_list, size_t token_list_len, - Stage1AirInst **input_list, Stage1AirInst **output_types, ZigVar **output_vars, size_t return_count, - bool has_side_effects, ZigType *return_type) -{ - Stage1AirInstAsm *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = return_type; - instruction->asm_template = asm_template; - instruction->token_list = token_list; - instruction->token_list_len = token_list_len; - instruction->input_list = input_list; - instruction->output_types = output_types; - instruction->output_vars = output_vars; - instruction->return_count = return_count; - instruction->has_side_effects = has_side_effects; - - assert(source_node->type == NodeTypeAsmExpr); - for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { - Stage1AirInst *output_type = output_types[i]; - if (output_type) ir_ref_inst_gen(output_type); - } - - for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { - Stage1AirInst *input_value = input_list[i]; - ir_ref_inst_gen(input_value); - } - - return &instruction->base; -} - -static Stage1AirInst *ir_build_test_non_null_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - Stage1AirInstTestNonNull *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_bool; - inst->value = value; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_optional_unwrap_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing, ZigType *result_type) -{ - Stage1AirInstOptionalUnwrapPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = result_type; - inst->base_ptr = base_ptr; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_inst_gen(base_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_optional_wrap(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_ty, - Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstOptionalWrap *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_ty; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_wrap_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstErrWrapPayload *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_wrap_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstErrWrapCode *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_clz_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, Stage1AirInst *op) { - Stage1AirInstClz *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ctz_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, Stage1AirInst *op) { - Stage1AirInstCtz *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_pop_count_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *op) -{ - Stage1AirInstPopCount *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bswap_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *op_type, - Stage1AirInst *op) -{ - Stage1AirInstBswap *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = op_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bit_reverse_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *int_type, - Stage1AirInst *op) -{ - Stage1AirInstBitReverse *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = int_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInstSwitchBr *ir_build_switch_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target_value, Stage1AirBasicBlock *else_block, size_t case_count, Stage1AirInstSwitchBrCase *cases) -{ - Stage1AirInstSwitchBr *instruction = ir_build_inst_noreturn(&ira->new_irb, - scope, source_node); - instruction->target_value = target_value; - instruction->else_block = else_block; - instruction->case_count = case_count; - instruction->cases = cases; - - ir_ref_inst_gen(target_value); - - for (size_t i = 0; i < case_count; i += 1) { - ir_ref_inst_gen(cases[i].value); - } - - return instruction; -} - -static Stage1AirInst *ir_build_union_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *tag_type) -{ - Stage1AirInstUnionTag *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->value = value; - instruction->base.value->type = tag_type; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ref_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstRef *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_name_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *str_type) -{ - Stage1AirInstErrName *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = str_type; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_cmpxchg_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *ptr, Stage1AirInst *cmp_value, Stage1AirInst *new_value, - AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, Stage1AirInst *result_loc) -{ - Stage1AirInstCmpxchg *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->ptr = ptr; - instruction->cmp_value = cmp_value; - instruction->new_value = new_value; - instruction->success_order = success_order; - instruction->failure_order = failure_order; - instruction->is_weak = is_weak; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(cmp_value); - ir_ref_inst_gen(new_value); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_fence_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, AtomicOrder order) { - Stage1AirInstFence *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->order = order; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_reduce_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ReduceOp op, Stage1AirInst *value, ZigType *result_type) { - Stage1AirInstReduce *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, Stage1AirBasicBlock *basic_block) { - assert(basic_block); - irb->current_basic_block = basic_block; -} - -static void ir_append_basic_block_gen(IrBuilderGen *irb, Stage1AirBasicBlock *bb) { - assert(!bb->already_appended); - bb->already_appended = true; - irb->exec->basic_block_list.append(bb); -} - -static void ir_set_cursor_at_end_and_append_block_gen(IrBuilderGen *irb, Stage1AirBasicBlock *basic_block) { - ir_append_basic_block_gen(irb, basic_block); - ir_set_cursor_at_end_gen(irb, basic_block); -} - -static Stage1AirInst *ir_build_suspend_begin_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstSuspendBegin *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_save_err_ret_addr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstSaveErrRetAddr *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_truncate_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *dest_type, - Stage1AirInst *target) -{ - Stage1AirInstTruncate *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = dest_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_shuffle_vector_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *a, Stage1AirInst *b, Stage1AirInst *mask) -{ - Stage1AirInstShuffleVector *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->a = a; - inst->b = b; - inst->mask = mask; - - ir_ref_inst_gen(a); - ir_ref_inst_gen(b); - ir_ref_inst_gen(mask); - - return &inst->base; -} - -static Stage1AirInst *ir_build_select_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *pred, Stage1AirInst *a, Stage1AirInst *b) -{ - Stage1AirInstSelect *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->pred = pred; - inst->a = a; - inst->b = b; - - ir_ref_inst_gen(pred); - ir_ref_inst_gen(a); - ir_ref_inst_gen(b); - - return &inst->base; -} - -static Stage1AirInst *ir_build_splat_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *scalar) -{ - Stage1AirInstSplat *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->scalar = scalar; - - ir_ref_inst_gen(scalar); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bool_not_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - Stage1AirInstBoolNot *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_memset_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *dest_ptr, Stage1AirInst *byte, Stage1AirInst *count) -{ - Stage1AirInstMemset *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->byte = byte; - instruction->count = count; - - ir_ref_inst_gen(dest_ptr); - ir_ref_inst_gen(byte); - ir_ref_inst_gen(count); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_memcpy_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *dest_ptr, Stage1AirInst *src_ptr, Stage1AirInst *count) -{ - Stage1AirInstMemcpy *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->src_ptr = src_ptr; - instruction->count = count; - - ir_ref_inst_gen(dest_ptr); - ir_ref_inst_gen(src_ptr); - ir_ref_inst_gen(count); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_slice_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *slice_type, - Stage1AirInst *ptr, Stage1AirInst *start, Stage1AirInst *end, bool safety_check_on, Stage1AirInst *result_loc, - ZigValue *sentinel) -{ - Stage1AirInstSlice *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = slice_type; - instruction->ptr = ptr; - instruction->start = start; - instruction->end = end; - instruction->safety_check_on = safety_check_on; - instruction->result_loc = result_loc; - instruction->sentinel = sentinel; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(start); - if (end != nullptr) ir_ref_inst_gen(end); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_breakpoint_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstBreakpoint *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &instruction->base; -} - -static Stage1AirInst *ir_build_return_address_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstReturnAddress *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - return &inst->base; -} - -static Stage1AirInst *ir_build_frame_address_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstFrameAddress *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - return &inst->base; -} - -static Stage1AirInst *ir_build_handle_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstFrameHandle *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ty; - return &inst->base; -} - -static Stage1AirInst *ir_build_frame_size_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *fn) -{ - Stage1AirInstFrameSize *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - inst->fn = fn; - - ir_ref_inst_gen(fn); - - return &inst->base; -} - -static Stage1AirInst *ir_build_overflow_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - IrOverflowOp op, Stage1AirInst *op1, Stage1AirInst *op2, Stage1AirInst *result_ptr, - ZigType *result_ptr_type) -{ - Stage1AirInstOverflowOp *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->op = op; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->result_ptr = result_ptr; - instruction->result_ptr_type = result_ptr_type; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - ir_ref_inst_gen(result_ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_float_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - BuiltinFnId fn_id, ZigType *operand_type) -{ - Stage1AirInstFloatOp *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = operand_type; - instruction->operand = operand; - instruction->fn_id = fn_id; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_mul_add_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *op1, Stage1AirInst *op2, - Stage1AirInst *op3, ZigType *expr_type) -{ - Stage1AirInstMulAdd *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->op3 = op3; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - ir_ref_inst_gen(op3); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_test_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *err_union) { - Stage1AirInstTestErr *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->err_union = err_union; - - ir_ref_inst_gen(err_union); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_unwrap_err_code_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *err_union_ptr, ZigType *result_type) -{ - Stage1AirInstUnwrapErrCode *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->err_union_ptr = err_union_ptr; - - ir_ref_inst_gen(err_union_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_unwrap_err_payload_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, bool safety_check_on, bool initializing, ZigType *result_type) -{ - Stage1AirInstUnwrapErrPayload *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->value = value; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_ptr_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *ptr_type, Stage1AirInst *ptr, bool safety_check_on) -{ - Stage1AirInstPtrCast *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ptr_type; - instruction->ptr = ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_inst_gen(ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bit_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *operand, ZigType *ty) -{ - Stage1AirInstBitCast *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - instruction->operand = operand; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstWidenOrShorten *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->target = target; - - ir_ref_inst_gen(target); - - return &inst->base; -} - -static Stage1AirInst *ir_build_int_to_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *ptr_type) -{ - Stage1AirInstIntToPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = ptr_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ptr_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target) { - Stage1AirInstPtrToInt *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - inst->target = target; - - ir_ref_inst_gen(target); - - return &inst->base; -} - -static Stage1AirInst *ir_build_int_to_enum_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, Stage1AirInst *target) -{ - Stage1AirInstIntToEnum *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = dest_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_int_to_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - Stage1AirInstIntToErr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = wanted_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - Stage1AirInstErrToInt *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = wanted_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_panic_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *msg) { - Stage1AirInstPanic *instruction = ir_build_inst_noreturn(&ira->new_irb, - scope, source_node); - instruction->msg = msg; - - ir_ref_inst_gen(msg); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_tag_name_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstTagName *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_field_parent_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *field_ptr, TypeStructField *field, ZigType *result_type) -{ - Stage1AirInstFieldParentPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = result_type; - inst->field_ptr = field_ptr; - inst->field = field; - - ir_ref_inst_gen(field_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_align_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstAlignCast *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_error_return_trace_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - IrInstErrorReturnTraceOptional optional, ZigType *result_type) -{ - Stage1AirInstErrorReturnTrace *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->optional = optional; - - return &inst->base; -} - -static Stage1AirInst *ir_build_atomic_rmw_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type) -{ - Stage1AirInstAtomicRmw *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = operand_type; - instruction->ptr = ptr; - instruction->op = op; - instruction->operand = operand; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_atomic_load_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AtomicOrder ordering, ZigType *operand_type) -{ - Stage1AirInstAtomicLoad *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = operand_type; - instruction->ptr = ptr; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_atomic_store_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *value, AtomicOrder ordering) -{ - Stage1AirInstAtomicStore *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(value); - - return &instruction->base; -} - - -static Stage1AirInst *ir_build_vector_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *vector, Stage1AirInst *result_loc) -{ - Stage1AirInstVectorToArray *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->vector = vector; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(vector); - ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstPtrOfArrayToSlice *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_array_to_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array, ZigType *result_type) -{ - Stage1AirInstArrayToVector *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->array = array; - - ir_ref_inst_gen(array); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_assert_zero(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target) -{ - Stage1AirInstAssertZero *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_void; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_assert_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target) -{ - Stage1AirInstAssertNonNull *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_void; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInstAlloca *ir_build_alloca_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - uint32_t align, const char *name_hint) -{ - Stage1AirInstAlloca *instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - instruction->align = align; - instruction->name_hint = name_hint; - - return instruction; -} - -static Stage1AirInst *ir_build_suspend_finish_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInstSuspendBegin *begin) { - Stage1AirInstSuspendFinish *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - inst->begin = begin; - - ir_ref_inst_gen(&begin->base); - - return &inst->base; -} - -static Stage1AirInstAwait *ir_build_await_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame, ZigType *result_type, Stage1AirInst *result_loc, bool is_nosuspend) -{ - Stage1AirInstAwait *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->frame = frame; - instruction->result_loc = result_loc; - instruction->is_nosuspend = is_nosuspend; - - ir_ref_inst_gen(frame); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return instruction; -} - -static Stage1AirInst *ir_build_resume_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *frame) { - Stage1AirInstResume *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->frame = frame; - - ir_ref_inst_gen(frame); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_spill_begin_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - SpillId spill_id) -{ - Stage1AirInstSpillBegin *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->operand = operand; - instruction->spill_id = spill_id; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_spill_end_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInstSpillBegin *begin, - ZigType *result_type) -{ - Stage1AirInstSpillEnd *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->begin = begin; - - ir_ref_inst_gen(&begin->base); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_vector_extract_elem(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector, Stage1AirInst *index) -{ - Stage1AirInstVectorExtractElem *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = vector->value->type->data.vector.elem_type; - instruction->vector = vector; - instruction->index = index; - - ir_ref_inst_gen(vector); - ir_ref_inst_gen(index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_wasm_memory_size_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *index) { - Stage1AirInstWasmMemorySize *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_u32; - instruction->index = index; - - ir_ref_inst_gen(index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *index, Stage1AirInst *delta) { - Stage1AirInstWasmMemoryGrow *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_i32; - instruction->index = index; - instruction->delta = delta; - - ir_ref_inst_gen(index); - ir_ref_inst_gen(delta); - - return &instruction->base; -} - -static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template, - ZigList *tok_list) -{ - // TODO Connect the errors in this function back up to the actual source location - // rather than just the token. https://github.com/ziglang/zig/issues/2080 - enum State { - StateStart, - StatePercent, - StateTemplate, - StateVar, - }; - - assert(tok_list->length == 0); - - AsmToken *cur_tok = nullptr; - - enum State state = StateStart; - - for (size_t i = 0; i < buf_len(asm_template); i += 1) { - uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i); - switch (state) { - case StateStart: - if (c == '%') { - tok_list->add_one(); - cur_tok = &tok_list->last(); - cur_tok->id = AsmTokenIdPercent; - cur_tok->start = i; - state = StatePercent; - } else { - tok_list->add_one(); - cur_tok = &tok_list->last(); - cur_tok->id = AsmTokenIdTemplate; - cur_tok->start = i; - state = StateTemplate; - } - break; - case StatePercent: - if (c == '%') { - cur_tok->end = i; - state = StateStart; - } else if (c == '[') { - cur_tok->id = AsmTokenIdVar; - state = StateVar; - } else if (c == '=') { - cur_tok->id = AsmTokenIdUniqueId; - cur_tok->end = i; - state = StateStart; - } else { - add_node_error(ira->codegen, source_node, - buf_create_from_str("expected a '%' or '['")); - return ErrorSemanticAnalyzeFail; - } - break; - case StateTemplate: - if (c == '%') { - cur_tok->end = i; - i -= 1; - cur_tok = nullptr; - state = StateStart; - } - break; - case StateVar: - if (c == ']') { - cur_tok->end = i; - state = StateStart; - } else if ((c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - (c == '_')) - { - // do nothing - } else { - add_node_error(ira->codegen, source_node, - buf_sprintf("invalid substitution character: '%c'", c)); - return ErrorSemanticAnalyzeFail; - } - break; - } - } - - switch (state) { - case StateStart: - break; - case StatePercent: - case StateVar: - add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template")); - return ErrorSemanticAnalyzeFail; - case StateTemplate: - cur_tok->end = buf_len(asm_template); - break; - } - return ErrorNone; -} - -// errors should be populated with set1's values -static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigType *set1, ZigType *set2, - Buf *type_name) -{ - assert(set1->id == ZigTypeIdErrorSet); - assert(set2->id == ZigTypeIdErrorSet); - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - if (type_name == nullptr) { - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - } else { - buf_init_from_buf(&err_set_type->name, type_name); - } - - for (uint32_t i = 0, count = set1->data.error_set.err_count; i < count; i += 1) { - assert(errors[set1->data.error_set.errors[i]->value] == set1->data.error_set.errors[i]); - } - - uint32_t count = set1->data.error_set.err_count; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - if (errors[error_entry->value] == nullptr) { - count += 1; - } - } - - err_set_type->data.error_set.err_count = count; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(count); - - bool need_comma = false; - for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set1->data.error_set.errors[i]; - if (type_name == nullptr) { - const char *comma = need_comma ? "," : ""; - need_comma = true; - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&error_entry->name)); - } - err_set_type->data.error_set.errors[i] = error_entry; - } - - uint32_t index = set1->data.error_set.err_count; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - if (errors[error_entry->value] == nullptr) { - errors[error_entry->value] = error_entry; - if (type_name == nullptr) { - const char *comma = need_comma ? "," : ""; - need_comma = true; - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&error_entry->name)); - } - err_set_type->data.error_set.errors[index] = error_entry; - index += 1; - } - } - assert(index == count); - - if (type_name == nullptr) { - buf_appendf(&err_set_type->name, "}"); - } - - return err_set_type; - -} - -static ZigType *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node, - ErrorTableEntry *err_entry) -{ - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name)); - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - err_set_type->data.error_set.err_count = 1; - err_set_type->data.error_set.errors = heap::c_allocator.create(); - - err_set_type->data.error_set.errors[0] = err_entry; - - return err_set_type; -} - -static void invalidate_exec_gen(Stage1Air *exec, ErrorMsg *msg) { - if (exec->first_err_trace_msg != nullptr) - return; - - exec->first_err_trace_msg = msg; - - for (size_t i = 0; i < exec->tld_list.length; i += 1) { - exec->tld_list.items[i]->resolution = TldResolutionInvalid; - } - - if (exec->source_exec != nullptr) - invalidate_exec(exec->source_exec, msg); -} - - -static ErrorMsg *exec_add_error_node_gen(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, Buf *msg) { - ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - invalidate_exec_gen(exec, err_msg); - if (exec->parent_exec) { - ir_add_call_stack_errors_gen(codegen, exec, err_msg, 10); - } - return err_msg; -} - -static ErrorMsg *ir_add_error_node(IrAnalyze *ira, AstNode *source_node, Buf *msg) { - return exec_add_error_node_gen(ira->codegen, ira->new_irb.exec, source_node, msg); -} - -static ErrorMsg *opt_ir_add_error_node(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, Buf *msg) { - if (ira != nullptr) - return exec_add_error_node_gen(codegen, ira->new_irb.exec, source_node, msg); - else - return add_node_error(codegen, source_node, msg); -} - -static ErrorMsg *ir_add_error(IrAnalyze *ira, Stage1AirInst *source_instruction, Buf *msg) { - return ir_add_error_node(ira, source_instruction->source_node, msg); -} - -// This function takes a comptime ptr and makes the child const value conform to the type -// described by the pointer. -static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *ptr_val) -{ - Error err; - assert(ptr_val->type->id == ZigTypeIdPointer); - assert(ptr_val->special == ConstValSpecialStatic); - ZigValue tmp = {}; - tmp.special = ConstValSpecialStatic; - tmp.type = ptr_val->type->data.pointer.child_type; - if ((err = ir_read_const_ptr(ira, codegen, source_node, &tmp, ptr_val))) - return err; - ZigValue *child_val = const_ptr_pointee_unchecked(codegen, ptr_val); - copy_const_val(codegen, child_val, &tmp); - return ErrorNone; -} - -ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val, - AstNode *source_node) -{ - Error err; - ZigValue *val = const_ptr_pointee_unchecked(codegen, const_val); - if (val == nullptr) return nullptr; - assert(const_val->type->id == ZigTypeIdPointer); - ZigType *expected_type = const_val->type->data.pointer.child_type; - if (expected_type == codegen->builtin_types.entry_anytype) { - return val; - } - switch (type_has_one_possible_value(codegen, expected_type)) { - case OnePossibleValueInvalid: - return nullptr; - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - return get_the_one_possible_value(codegen, expected_type); - } - if (!types_have_same_zig_comptime_repr(codegen, expected_type, val->type)) { - if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val))) - return nullptr; - return const_ptr_pointee_unchecked(codegen, const_val); - } - return val; -} - -static Error ir_exec_scan_for_side_effects(CodeGen *codegen, Stage1Air *exec) { - Stage1AirBasicBlock *bb = exec->basic_block_list.at(0); - for (size_t i = 0; i < bb->instruction_list.length; i += 1) { - Stage1AirInst *instruction = bb->instruction_list.at(i); - if (instruction->id == Stage1AirInstIdReturn) { - return ErrorNone; - } else if (ir_inst_gen_has_side_effects(instruction)) { - if (instr_is_comptime(instruction)) { - switch (instruction->id) { - case Stage1AirInstIdUnwrapErrPayload: - case Stage1AirInstIdOptionalUnwrapPtr: - case Stage1AirInstIdUnionFieldPtr: - continue; - default: - break; - } - } - if (get_scope_typeof(instruction->scope) != nullptr) { - // doesn't count, it's inside a @TypeOf() - continue; - } - exec_add_error_node_gen(codegen, exec, instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ErrorSemanticAnalyzeFail; - } - } - zig_unreachable(); -} - -static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, Stage1ZirInst* source_instruction) { - if (ir_should_inline(ira->zir, source_instruction->scope)) { - ir_add_error_node(ira, source_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); - return false; - } - return true; -} - -static bool const_val_fits_in_num_lit(ZigValue *const_val, ZigType *num_lit_type) { - return ((num_lit_type->id == ZigTypeIdComptimeFloat && - (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat)) || - (num_lit_type->id == ZigTypeIdComptimeInt && - (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt))); -} - -static bool float_has_fraction(ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_has_fraction(&const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - { - float16_t floored = f16_roundToInt(const_val->data.x_f16, softfloat_round_minMag, false); - return !f16_eq(floored, const_val->data.x_f16); - } - case 32: - return floorf(const_val->data.x_f32) != const_val->data.x_f32; - case 64: - return floor(const_val->data.x_f64) != const_val->data.x_f64; - case 80: - { - extFloat80_t floored; - extF80M_roundToInt(&const_val->data.x_f80, softfloat_round_minMag, false, &floored); - return !extF80M_eq(&floored, &const_val->data.x_f80); - } - case 128: - { - float128_t floored; - f128M_roundToInt(&const_val->data.x_f128, softfloat_round_minMag, false, &floored); - return !f128M_eq(&floored, &const_val->data.x_f128); - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_append_buf(Buf *buf, ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_append_buf(buf, &const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16)); - break; - case 32: - buf_appendf(buf, "%f", const_val->data.x_f32); - break; - case 64: - buf_appendf(buf, "%f", const_val->data.x_f64); - break; - case 80: - { - float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - buf_appendf(buf, "%f", const_val->data.x_f64); - break; - } - case 128: - { - // TODO actual implementation - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - - float64_t f64_value = f128M_to_f64(&const_val->data.x_f128); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_bigint(BigInt *bigint, ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - { - double x = zig_f16_to_double(const_val->data.x_f16); - if (x >= 0) { - bigint_init_unsigned(bigint, (uint64_t)x); - } else { - bigint_init_unsigned(bigint, (uint64_t)-x); - bigint->is_negative = true; - } - break; - } - case 32: - if (const_val->data.x_f32 >= 0) { - bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32)); - } else { - bigint_init_unsigned(bigint, (uint64_t)(-const_val->data.x_f32)); - bigint->is_negative = true; - } - break; - case 64: - if (const_val->data.x_f64 >= 0) { - bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f64)); - } else { - bigint_init_unsigned(bigint, (uint64_t)(-const_val->data.x_f64)); - bigint->is_negative = true; - } - break; - case 80: - { - float128_t f128_value; - extF80M_to_f128M(&const_val->data.x_f80, &f128_value); - BigFloat tmp_float; - bigfloat_init_128(&tmp_float, f128_value); - bigint_init_bigfloat(bigint, &tmp_float); - } - break; - case 128: - { - BigFloat tmp_float; - bigfloat_init_128(&tmp_float, const_val->data.x_f128); - bigint_init_bigfloat(bigint, &tmp_float); - } - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_bigfloat(ZigValue *dest_val, BigFloat *bigfloat) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = bigfloat_to_f16(bigfloat); - break; - case 32: - dest_val->data.x_f32 = bigfloat_to_f32(bigfloat); - break; - case 64: - dest_val->data.x_f64 = bigfloat_to_f64(bigfloat); - break; - case 80: { - float128_t f128_value = bigfloat_to_f128(bigfloat); - f128M_to_extF80M(&f128_value, &dest_val->data.x_f80); - break; - } - case 128: - dest_val->data.x_f128 = bigfloat_to_f128(bigfloat); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f16(ZigValue *dest_val, float16_t x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_16(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = x; - break; - case 32: - dest_val->data.x_f32 = zig_f16_to_double(x); - break; - case 64: - dest_val->data.x_f64 = zig_f16_to_double(x); - break; - case 80: - f16_to_extF80M(x, &dest_val->data.x_f80); - break; - case 128: - f16_to_f128M(x, &dest_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f32(ZigValue *dest_val, float x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_32(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = zig_double_to_f16(x); - break; - case 32: - dest_val->data.x_f32 = x; - break; - case 64: - dest_val->data.x_f64 = x; - break; - case 80: { - float32_t x_f32; - memcpy(&x_f32, &x, sizeof(float)); - f32_to_extF80M(x_f32, &dest_val->data.x_f80); - break; - } - case 128: - { - float32_t x_f32; - memcpy(&x_f32, &x, sizeof(float)); - f32_to_f128M(x_f32, &dest_val->data.x_f128); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f64(ZigValue *dest_val, double x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_64(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = zig_double_to_f16(x); - break; - case 32: - dest_val->data.x_f32 = x; - break; - case 64: - dest_val->data.x_f64 = x; - break; - case 80: { - float64_t x_f64; - memcpy(&x_f64, &x, sizeof(double)); - f64_to_extF80M(x_f64, &dest_val->data.x_f80); - break; - } - case 128: - { - float64_t x_f64; - memcpy(&x_f64, &x, sizeof(double)); - f64_to_f128M(x_f64, &dest_val->data.x_f128); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f128(ZigValue *dest_val, float128_t x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_128(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = f128M_to_f16(&x); - break; - case 32: - { - float32_t f32_val = f128M_to_f32(&x); - memcpy(&dest_val->data.x_f32, &f32_val, sizeof(float)); - break; - } - case 64: - { - float64_t f64_val = f128M_to_f64(&x); - memcpy(&dest_val->data.x_f64, &f64_val, sizeof(double)); - break; - } - case 80: - f128M_to_extF80M(&x, &dest_val->data.x_f80); - break; - case 128: - { - memcpy(&dest_val->data.x_f128, &x, sizeof(float128_t)); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_float(ZigValue *dest_val, ZigValue *src_val) { - if (src_val->type->id == ZigTypeIdComptimeFloat) { - float_init_bigfloat(dest_val, &src_val->data.x_bigfloat); - } else if (src_val->type->id == ZigTypeIdFloat) { - switch (src_val->type->data.floating.bit_count) { - case 16: - float_init_f16(dest_val, src_val->data.x_f16); - break; - case 32: - float_init_f32(dest_val, src_val->data.x_f32); - break; - case 64: - float_init_f64(dest_val, src_val->data.x_f64); - break; - case 80: { - float128_t f128_value; - extF80M_to_f128M(&src_val->data.x_f80, &f128_value); - float_init_f128(dest_val, f128_value); - break; - } - case 128: - float_init_f128(dest_val, src_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static bool float_is_nan(ZigValue *op) { - if (op->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_is_nan(&op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - return zig_f16_isNaN(op->data.x_f16); - case 32: - return op->data.x_f32 != op->data.x_f32; - case 64: - return op->data.x_f64 != op->data.x_f64; - case 80: - return zig_extF80_isNaN(&op->data.x_f80); - case 128: - return zig_f128_isNaN(&op->data.x_f128); - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static Cmp float_cmp(ZigValue *op1, ZigValue *op2) { - if (op1->type == op2->type) { - if (op1->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (f16_lt(op1->data.x_f16, op2->data.x_f16)) { - return CmpLT; - } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) { - return CmpGT; - } else { - return CmpEQ; - } - case 32: - if (op1->data.x_f32 > op2->data.x_f32) { - return CmpGT; - } else if (op1->data.x_f32 < op2->data.x_f32) { - return CmpLT; - } else { - return CmpEQ; - } - case 64: - if (op1->data.x_f64 > op2->data.x_f64) { - return CmpGT; - } else if (op1->data.x_f64 < op2->data.x_f64) { - return CmpLT; - } else { - return CmpEQ; - } - case 80: - if (extF80M_lt(&op1->data.x_f80, &op2->data.x_f80)) { - return CmpLT; - } else if (extF80M_eq(&op1->data.x_f80, &op2->data.x_f80)) { - return CmpEQ; - } else { - return CmpGT; - } - case 128: - if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) { - return CmpLT; - } else if (f128M_eq(&op1->data.x_f128, &op2->data.x_f128)) { - return CmpEQ; - } else { - return CmpGT; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } - } - BigFloat op1_big; - BigFloat op2_big; - value_to_bigfloat(&op1_big, op1); - value_to_bigfloat(&op2_big, op2); - return bigfloat_cmp(&op1_big, &op2_big); -} - -// This function cannot handle NaN -static Cmp float_cmp_zero(ZigValue *op) { - if (op->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_cmp_zero(&op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - { - const float16_t zero = zig_double_to_f16(0); - if (f16_lt(op->data.x_f16, zero)) { - return CmpLT; - } else if (f16_lt(zero, op->data.x_f16)) { - return CmpGT; - } else { - return CmpEQ; - } - } - case 32: - if (op->data.x_f32 < 0.0) { - return CmpLT; - } else if (op->data.x_f32 > 0.0) { - return CmpGT; - } else { - return CmpEQ; - } - case 64: - if (op->data.x_f64 < 0.0) { - return CmpLT; - } else if (op->data.x_f64 > 0.0) { - return CmpGT; - } else { - return CmpEQ; - } - case 80: { - extFloat80_t zero_float; - ui32_to_extF80M(0, &zero_float); - if (extF80M_lt(&op->data.x_f80, &zero_float)) { - return CmpLT; - } else if (extF80M_eq(&op->data.x_f80, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } - } - case 128: { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(&op->data.x_f128, &zero_float)) { - return CmpLT; - } else if (f128M_eq(&op->data.x_f128, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_add(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_add(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 + op2->data.x_f64; - return; - case 80: - extF80M_add(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_add(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_sub(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_sub(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 - op2->data.x_f64; - return; - case 80: - extF80M_sub(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_sub(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_mul(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_mul(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 * op2->data.x_f64; - return; - case 80: - extF80M_mul(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_mul(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64; - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div_trunc(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_minMag, false); - return; - case 32: - out_val->data.x_f32 = truncf(op1->data.x_f32 / op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64); - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_minMag, false, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - f128M_roundToInt(&out_val->data.x_f128, softfloat_round_minMag, false, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div_floor(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_min, false); - return; - case 32: - out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = floor(op1->data.x_f64 / op2->data.x_f64); - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_min, false, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - f128M_roundToInt(&out_val->data.x_f128, softfloat_round_min, false, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -// c = a - b * trunc(a / b) -static float16_t zig_f16_rem(float16_t a, float16_t b) { - float16_t c; - c = f16_div(a, b); - c = f16_roundToInt(c, softfloat_round_minMag, false); - c = f16_mul(b, c); - c = f16_sub(a, c); - return c; -} - -// c = a - b * trunc(a / b) -static void zig_f128M_rem(const float128_t* a, const float128_t* b, float128_t* c) { - f128M_div(a, b, c); - f128M_roundToInt(c, softfloat_round_minMag, false, c); - f128M_mul(b, c, c); - f128M_sub(a, c, c); -} - -// c = a - b * trunc(a / b) -static void zig_extF80M_rem(const extFloat80_t* a, const extFloat80_t* b, extFloat80_t* c) { - extF80M_div(a, b, c); - extF80M_roundToInt(c, softfloat_round_minMag, false, c); - extF80M_mul(b, c, c); - extF80M_sub(a, c, c); -} - -static void float_rem(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = zig_f16_rem(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = fmod(op1->data.x_f64, op2->data.x_f64); - return; - case 80: - zig_extF80M_rem(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - zig_f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -// c = a - b * trunc(a / b) -static float16_t zig_f16_mod(float16_t a, float16_t b) { - float16_t c; - c = f16_div(a, b); - c = f16_roundToInt(c, softfloat_round_min, true); - c = f16_mul(b, c); - c = f16_sub(a, c); - return c; -} - -// c = a - b * trunc(a / b) -static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* c) { - f128M_div(a, b, c); - f128M_roundToInt(c, softfloat_round_min, true, c); - f128M_mul(b, c, c); - f128M_sub(a, c, c); -} - -// c = a - b * trunc(a / b) -static void zig_extF80M_mod(const extFloat80_t* a, const extFloat80_t* b, extFloat80_t* c) { - extF80M_div(a, b, c); - extF80M_roundToInt(c, softfloat_round_min, true, c); - extF80M_mul(b, c, c); - extF80M_sub(a, c, c); -} - -static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = zig_f16_mod(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64); - return; - case 80: - zig_extF80M_mod(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_max(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (zig_f16_isNaN(op1->data.x_f16)) { - out_val->data.x_f16 = op2->data.x_f16; - } else if (zig_f16_isNaN(op2->data.x_f16)) { - out_val->data.x_f16 = op1->data.x_f16; - } else { - out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op2->data.x_f16 : op1->data.x_f16; - } - return; - case 32: - if (op1->data.x_f32 != op1->data.x_f32) { - out_val->data.x_f32 = op2->data.x_f32; - } else if (op2->data.x_f32 != op2->data.x_f32) { - out_val->data.x_f32 = op1->data.x_f32; - } else { - out_val->data.x_f32 = op1->data.x_f32 > op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; - } - return; - case 64: - if (op1->data.x_f64 != op1->data.x_f64) { - out_val->data.x_f64 = op2->data.x_f64; - } else if (op2->data.x_f64 != op2->data.x_f64) { - out_val->data.x_f64 = op1->data.x_f64; - } else { - out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; - } - return; - case 80: - if (zig_extF80_isNaN(&op1->data.x_f80)) { - out_val->data.x_f80 = op2->data.x_f80; - } else if (zig_extF80_isNaN(&op2->data.x_f80)) { - out_val->data.x_f80 = op1->data.x_f80; - } else { - out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op2->data.x_f80 : op1->data.x_f80; - } - return; - case 128: - if (zig_f128_isNaN(&op1->data.x_f128)) { - out_val->data.x_f128 = op2->data.x_f128; - } else if (zig_f128_isNaN(&op2->data.x_f128)) { - out_val->data.x_f128 = op1->data.x_f128; - } else { - out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op2->data.x_f128 : op1->data.x_f128; - } - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_min(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (zig_f16_isNaN(op1->data.x_f16)) { - out_val->data.x_f16 = op2->data.x_f16; - } else if (zig_f16_isNaN(op2->data.x_f16)) { - out_val->data.x_f16 = op1->data.x_f16; - } else { - out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op1->data.x_f16 : op2->data.x_f16; - } - return; - case 32: - if (op1->data.x_f32 != op1->data.x_f32) { - out_val->data.x_f32 = op2->data.x_f32; - } else if (op2->data.x_f32 != op2->data.x_f32) { - out_val->data.x_f32 = op1->data.x_f32; - } else { - out_val->data.x_f32 = op1->data.x_f32 < op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; - } - return; - case 64: - if (op1->data.x_f64 != op1->data.x_f64) { - out_val->data.x_f64 = op2->data.x_f64; - } else if (op2->data.x_f64 != op2->data.x_f64) { - out_val->data.x_f64 = op1->data.x_f64; - } else { - out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; - } - return; - case 80: - if (zig_extF80_isNaN(&op1->data.x_f80)) { - out_val->data.x_f80 = op2->data.x_f80; - } else if (zig_extF80_isNaN(&op2->data.x_f80)) { - out_val->data.x_f80 = op1->data.x_f80; - } else { - out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op1->data.x_f80 : op2->data.x_f80; - } - return; - case 128: - if (zig_f128_isNaN(&op1->data.x_f128)) { - out_val->data.x_f128 = op2->data.x_f128; - } else if (zig_f128_isNaN(&op2->data.x_f128)) { - out_val->data.x_f128 = op1->data.x_f128; - } else { - out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op1->data.x_f128 : op2->data.x_f128; - } - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_negate(ZigValue *out_val, ZigValue *op) { - out_val->type = op->type; - if (op->type->id == ZigTypeIdComptimeFloat) { - bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_neg(op->data.x_f16); - return; - case 32: - out_val->data.x_f32 = -op->data.x_f32; - return; - case 64: - out_val->data.x_f64 = -op->data.x_f64; - return; - case 80: - extF80M_neg(&op->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_neg(&op->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -void float_write_ieee597(ZigValue *op, uint8_t *buf, bool target_is_big_endian) { - if (op->type->id != ZigTypeIdFloat) - zig_unreachable(); - - const unsigned n = op->type->data.floating.bit_count / 8; - assert(n <= 16); - - switch (op->type->data.floating.bit_count) { - case 16: - memcpy(buf, &op->data.x_f16, 2); - break; - case 32: - memcpy(buf, &op->data.x_f32, 4); - break; - case 64: - memcpy(buf, &op->data.x_f64, 8); - break; - case 80: - memcpy(buf, &op->data.x_f80, 16); - break; - case 128: - memcpy(buf, &op->data.x_f128, 16); - break; - default: - zig_unreachable(); - } - - // Byteswap if system endianness != target endianness - if (native_is_big_endian != target_is_big_endian) { - for (size_t i = 0; i < n / 2; i++) { - uint8_t u = buf[i]; - buf[i] = buf[n - 1 - i]; - buf[n - 1 - i] = u; - } - } -} - -void float_read_ieee597(ZigValue *val, uint8_t *buf, bool target_is_big_endian) { - if (val->type->id != ZigTypeIdFloat) - zig_unreachable(); - - const unsigned n = val->type->data.floating.bit_count / 8; - assert(n <= 16); - - uint8_t tmp[16]; - uint8_t *ptr = buf; - - // Byteswap if system endianness != target endianness - if (native_is_big_endian != target_is_big_endian) { - memcpy(tmp, buf, n); - for (size_t i = 0; i < n / 2; i++) { - uint8_t u = tmp[i]; - tmp[i] = tmp[n - 1 - i]; - tmp[n - 1 - i] = u; - } - - ptr = tmp; - } - - switch (val->type->data.floating.bit_count) { - case 16: - memcpy(&val->data.x_f16, ptr, 2); - return; - case 32: - memcpy(&val->data.x_f32, ptr, 4); - return; - case 64: - memcpy(&val->data.x_f64, ptr, 8); - return; - case 80: - memcpy(&val->data.x_f80, ptr, 16); - return; - case 128: - memcpy(&val->data.x_f128, ptr, 16); - return; - default: - zig_unreachable(); - } -} - -static void value_to_bigfloat(BigFloat *out, ZigValue *val) { - switch (val->type->id) { - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - bigfloat_init_bigint(out, &val->data.x_bigint); - return; - case ZigTypeIdComptimeFloat: - *out = val->data.x_bigfloat; - return; - case ZigTypeIdFloat: switch (val->type->data.floating.bit_count) { - case 16: - bigfloat_init_16(out, val->data.x_f16); - return; - case 32: - bigfloat_init_32(out, val->data.x_f32); - return; - case 64: - bigfloat_init_64(out, val->data.x_f64); - return; - case 80: { - float128_t f128_value; - extF80M_to_f128M(&val->data.x_f80, &f128_value); - bigfloat_init_128(out, f128_value); - return; - } - case 128: - bigfloat_init_128(out, val->data.x_f128); - return; - default: - zig_unreachable(); - } - default: - zig_unreachable(); - } -} - -static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruction, ZigType *other_type, - bool explicit_cast) -{ - if (type_is_invalid(other_type)) { - return false; - } - - ZigValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef); - if (const_val == nullptr) - return false; - - if (const_val->special == ConstValSpecialLazy) { - switch (const_val->data.x_lazy->id) { - case LazyValueIdAlignOf: { - // This is guaranteed to fit into a u29 - if (other_type->id == ZigTypeIdComptimeInt) - return true; - size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count; - if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && - other_type->data.integral.bit_count >= align_bits) - { - return true; - } - break; - } - case LazyValueIdSizeOf: { - // This is guaranteed to fit into a usize - if (other_type->id == ZigTypeIdComptimeInt) - return true; - size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count; - if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && - other_type->data.integral.bit_count >= usize_bits) - { - return true; - } - break; - } - default: - break; - } - } - - const_val = ir_resolve_const(ira, instruction, UndefBad); - if (const_val == nullptr) - return false; - - bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); - bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); - assert(const_val_is_int || const_val_is_float); - - if (const_val_is_int && other_type->id == ZigTypeIdComptimeFloat) { - return true; - } - if (other_type->id == ZigTypeIdFloat) { - if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { - return true; - } - if (const_val->type->id == ZigTypeIdInt) { - BigFloat tmp_bf; - bigfloat_init_bigint(&tmp_bf, &const_val->data.x_bigint); - BigFloat orig_bf; - switch (other_type->data.floating.bit_count) { - case 16: { - float16_t tmp = bigfloat_to_f16(&tmp_bf); - bigfloat_init_16(&orig_bf, tmp); - break; - } - case 32: { - float tmp = bigfloat_to_f32(&tmp_bf); - bigfloat_init_32(&orig_bf, tmp); - break; - } - case 64: { - double tmp = bigfloat_to_f64(&tmp_bf); - bigfloat_init_64(&orig_bf, tmp); - break; - } - case 80: { - float128_t tmp = bigfloat_to_f128(&tmp_bf); - extFloat80_t tmp80; - f128M_to_extF80M(&tmp, &tmp80); - extF80M_to_f128M(&tmp80, &tmp); - bigfloat_init_128(&orig_bf, tmp); - break; - } - case 128: { - float128_t tmp = bigfloat_to_f128(&tmp_bf); - bigfloat_init_128(&orig_bf, tmp); - break; - } - default: - zig_unreachable(); - } - BigInt orig_bi; - bigint_init_bigfloat(&orig_bi, &orig_bf); - if (bigint_cmp(&orig_bi, &const_val->data.x_bigint) == CmpEQ) { - return true; - } - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("type %s cannot represent integer value %s", - buf_ptr(&other_type->name), - buf_ptr(val_buf))); - return false; - } - if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) { - return true; - } - switch (other_type->data.floating.bit_count) { - case 16: - switch (const_val->type->data.floating.bit_count) { - case 32: { - float16_t tmp = zig_double_to_f16(const_val->data.x_f32); - float orig = zig_f16_to_double(tmp); - if (const_val->data.x_f32 == orig) { - return true; - } - break; - } - case 64: { - float16_t tmp = zig_double_to_f16(const_val->data.x_f64); - double orig = zig_f16_to_double(tmp); - if (const_val->data.x_f64 == orig) { - return true; - } - break; - } - case 80: { - float16_t tmp = extF80M_to_f16(&const_val->data.x_f80); - extFloat80_t orig; - f16_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float16_t tmp = f128M_to_f16(&const_val->data.x_f128); - float128_t orig; - f16_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 32: - switch (const_val->type->data.floating.bit_count) { - case 64: { - float tmp = const_val->data.x_f64; - double orig = tmp; - if (const_val->data.x_f64 == orig) { - return true; - } - break; - } - case 80: { - float32_t tmp = extF80M_to_f32(&const_val->data.x_f80); - extFloat80_t orig; - f32_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float32_t tmp = f128M_to_f32(&const_val->data.x_f128); - float128_t orig; - f32_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 64: - switch (const_val->type->data.floating.bit_count) { - case 80: { - float64_t tmp = extF80M_to_f64(&const_val->data.x_f80); - extFloat80_t orig; - f64_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float64_t tmp = f128M_to_f64(&const_val->data.x_f128); - float128_t orig; - f64_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 80: { - assert(const_val->type->data.floating.bit_count == 128); - extFloat80_t tmp; - f128M_to_extF80M(&const_val->data.x_f128, &tmp); - float128_t orig; - extF80M_to_f128M(&tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - case 128: - return true; - default: - zig_unreachable(); - } - Buf *val_buf = buf_alloc(); - float_append_buf(val_buf, const_val); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cast of value %s to type '%s' loses information", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } else if (other_type->id == ZigTypeIdInt && const_val_is_int) { - if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } - if (bigint_fits_in_bits(&const_val->data.x_bigint, other_type->data.integral.bit_count, - other_type->data.integral.is_signed)) - { - return true; - } - } else if (const_val_fits_in_num_lit(const_val, other_type)) { - return true; - } else if (other_type->id == ZigTypeIdOptional) { - ZigType *child_type = other_type->data.maybe.child_type; - if (const_val_fits_in_num_lit(const_val, child_type)) { - return true; - } else if (child_type->id == ZigTypeIdInt && const_val_is_int) { - if (!child_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'", - buf_ptr(val_buf), - buf_ptr(&child_type->name))); - return false; - } - if (bigint_fits_in_bits(&const_val->data.x_bigint, - child_type->data.integral.bit_count, - child_type->data.integral.is_signed)) - { - return true; - } - } else if (child_type->id == ZigTypeIdFloat && const_val_is_float) { - return true; - } - } - if (explicit_cast && (other_type->id == ZigTypeIdInt || other_type->id == ZigTypeIdComptimeInt) && - const_val_is_float) - { - if (float_has_fraction(const_val)) { - Buf *val_buf = buf_alloc(); - float_append_buf(val_buf, const_val); - - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("fractional component prevents float value %s from being casted to type '%s'", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } else { - if (other_type->id == ZigTypeIdComptimeInt) { - return true; - } else { - BigInt bigint; - float_init_bigint(&bigint, const_val); - if (bigint_fits_in_bits(&bigint, other_type->data.integral.bit_count, - other_type->data.integral.is_signed)) - { - return true; - } - } - } - } - - const char *num_lit_str; - Buf *val_buf = buf_alloc(); - if (const_val_is_float) { - num_lit_str = "float"; - float_append_buf(val_buf, const_val); - } else { - num_lit_str = "integer"; - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - } - - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("%s value %s cannot be coerced to type '%s'", - num_lit_str, - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; -} - -static bool is_tagged_union(ZigType *type) { - if (type->id != ZigTypeIdUnion) - return false; - return (type->data.unionation.decl_node->data.container_decl.auto_enum || - type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr); -} - -static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) { - assert(set->id == ZigTypeIdErrorSet); - for (uint32_t i = 0; i < set->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } -} - -static ErrorTableEntry *better_documented_error(ErrorTableEntry *preferred, ErrorTableEntry *other) { - if (preferred->decl_node->type == NodeTypeErrorSetField) - return preferred; - if (other->decl_node->type == NodeTypeErrorSetField) - return other; - return preferred; -} - -static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigType *set2, - AstNode *source_node) -{ - assert(set1->id == ZigTypeIdErrorSet); - assert(set2->id == ZigTypeIdErrorSet); - - if (!resolve_inferred_error_set(ira->codegen, set1, source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!resolve_inferred_error_set(ira->codegen, set2, source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_global_error_set(set1)) { - return set2; - } - if (type_is_global_error_set(set2)) { - return set1; - } - size_t errors_count = ira->codegen->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - populate_error_set_table(errors, set1); - ZigList intersection_list = {}; - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - - bool need_comma = false; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - ErrorTableEntry *existing_entry = errors[error_entry->value]; - if (existing_entry != nullptr) { - // prefer the one with docs - const char *comma = need_comma ? "," : ""; - need_comma = true; - ErrorTableEntry *existing_entry_with_docs = better_documented_error(existing_entry, error_entry); - intersection_list.append(existing_entry_with_docs); - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name)); - } - } - heap::c_allocator.deallocate(errors, errors_count); - - err_set_type->data.error_set.err_count = intersection_list.length; - err_set_type->data.error_set.errors = intersection_list.items; - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - - buf_appendf(&err_set_type->name, "}"); - - return err_set_type; -} - -static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, - ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) -{ - CodeGen *g = ira->codegen; - ConstCastOnly result = {}; - result.id = ConstCastResultIdOk; - - Error err; - - if (wanted_type == actual_type) - return result; - - // If pointers have the same representation in memory, they can be "const-casted". - // `const` attribute can be gained - // `volatile` attribute can be gained - // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) - // but only if !wanted_is_mutable - // alignment can be decreased - // bit offset attributes must match exactly - // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one - // sentinel-terminated pointers can coerce into PtrLenUnknown - ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); - ZigType *actual_ptr_type = get_src_ptr_type(actual_type); - bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(actual_type); - bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; - bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; - bool wanted_opt_or_ptr = wanted_ptr_type != nullptr && wanted_ptr_type->id == ZigTypeIdPointer; - bool actual_opt_or_ptr = actual_ptr_type != nullptr && actual_ptr_type->id == ZigTypeIdPointer; - if (wanted_opt_or_ptr && actual_opt_or_ptr) { - bool ok_null_term_ptrs = - wanted_ptr_type->data.pointer.sentinel == nullptr || - (actual_ptr_type->data.pointer.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, - actual_ptr_type->data.pointer.sentinel)) || - actual_ptr_type->data.pointer.ptr_len == PtrLenC; - if (!ok_null_term_ptrs) { - result.id = ConstCastResultIdPtrSentinel; - result.data.bad_ptr_sentinel = heap::c_allocator.allocate_nonzero(1); - result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; - result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; - return result; - } - bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; - if (!(ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr)) { - result.id = ConstCastResultIdPtrLens; - return result; - } - - bool ok_cv_qualifiers = - (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && - (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile); - if (!ok_cv_qualifiers) { - result.id = ConstCastResultIdCV; - result.data.bad_cv = heap::c_allocator.allocate_nonzero(1); - result.data.bad_cv->wanted_type = wanted_ptr_type; - result.data.bad_cv->actual_type = actual_ptr_type; - return result; - } - - ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, - actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdPointerChild; - result.data.pointer_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.pointer_mismatch->child = child; - result.data.pointer_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; - result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; - return result; - } - bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || !wanted_is_mutable)) || - (!wanted_allows_zero && !actual_allows_zero); - if (!ok_allows_zero) { - result.id = ConstCastResultIdBadAllowsZero; - result.data.bad_allows_zero = heap::c_allocator.allocate_nonzero(1); - result.data.bad_allows_zero->wanted_type = wanted_type; - result.data.bad_allows_zero->actual_type = actual_type; - return result; - } - if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, actual_type, ResolveStatusZeroBitsKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if (type_has_bits(g, wanted_type) == type_has_bits(g, actual_type) && - actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && - actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && - get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type)) - { - return result; - } - } - - // arrays - if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdArray && - wanted_type->data.array.len == actual_type->data.array.len) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.array.child_type, - actual_type->data.array.child_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdArrayChild; - result.data.array_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.array_mismatch->child = child; - result.data.array_mismatch->wanted_child = wanted_type->data.array.child_type; - result.data.array_mismatch->actual_child = actual_type->data.array.child_type; - return result; - } - bool ok_null_terminated = (wanted_type->data.array.sentinel == nullptr) || - (actual_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_type->data.array.sentinel, actual_type->data.array.sentinel)); - if (!ok_null_terminated) { - result.id = ConstCastResultIdSentinelArrays; - result.data.sentinel_arrays = heap::c_allocator.allocate_nonzero(1); - result.data.sentinel_arrays->child = child; - result.data.sentinel_arrays->wanted_type = wanted_type; - result.data.sentinel_arrays->actual_type = actual_type; - return result; - } - return result; - } - - // slice const - if (is_slice(wanted_type) && is_slice(actual_type)) { - ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - bool ok_sentinels = - wanted_ptr_type->data.pointer.sentinel == nullptr || - (actual_ptr_type->data.pointer.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, - actual_ptr_type->data.pointer.sentinel)); - if (!ok_sentinels) { - result.id = ConstCastResultIdPtrSentinel; - result.data.bad_ptr_sentinel = heap::c_allocator.allocate_nonzero(1); - result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; - result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; - return result; - } - if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && - (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && - actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && - actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && - get_ptr_align(g, actual_ptr_type) >= get_ptr_align(g, wanted_ptr_type)) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, - actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdSliceChild; - result.data.slice_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.slice_mismatch->child = child; - result.data.slice_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; - result.data.slice_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; - } - return result; - } - } - - // optional types - if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) { - // Consider the case where the wanted type is ??[*]T and the actual one - // is ?[*]T, we cannot turn the former into the latter even though the - // child types are compatible (?[*]T and [*]T are both represented as a - // pointer). The extra level of indirection in ??[*]T means it's - // represented as a regular, fat, optional type and, as a consequence, - // has a different shape than the one of ?[*]T. - if ((wanted_ptr_type != nullptr) != (actual_ptr_type != nullptr)) { - // The use of type_mismatch is intentional - result.id = ConstCastResultIdOptionalShape; - result.data.type_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.type_mismatch->wanted_type = wanted_type; - result.data.type_mismatch->actual_type = actual_type; - return result; - } - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, - actual_type->data.maybe.child_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdOptionalChild; - result.data.optional = heap::c_allocator.allocate_nonzero(1); - result.data.optional->child = child; - result.data.optional->wanted_child = wanted_type->data.maybe.child_type; - result.data.optional->actual_child = actual_type->data.maybe.child_type; - } - return result; - } - - // error union - if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorUnion) { - ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, - actual_type->data.error_union.payload_type, source_node, wanted_is_mutable); - if (payload_child.id == ConstCastResultIdInvalid) - return payload_child; - if (payload_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdErrorUnionPayload; - result.data.error_union_payload = heap::c_allocator.allocate_nonzero(1); - result.data.error_union_payload->child = payload_child; - result.data.error_union_payload->wanted_payload = wanted_type->data.error_union.payload_type; - result.data.error_union_payload->actual_payload = actual_type->data.error_union.payload_type; - return result; - } - ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type, - actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable); - if (error_set_child.id == ConstCastResultIdInvalid) - return error_set_child; - if (error_set_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdErrorUnionErrorSet; - result.data.error_union_error_set = heap::c_allocator.allocate_nonzero(1); - result.data.error_union_error_set->child = error_set_child; - result.data.error_union_error_set->wanted_err_set = wanted_type->data.error_union.err_set_type; - result.data.error_union_error_set->actual_err_set = actual_type->data.error_union.err_set_type; - return result; - } - return result; - } - - // error set - if (wanted_type->id == ZigTypeIdErrorSet && actual_type->id == ZigTypeIdErrorSet) { - ZigType *contained_set = actual_type; - ZigType *container_set = wanted_type; - - // if the container set is inferred, then this will always work. - if (container_set->data.error_set.infer_fn != nullptr && container_set->data.error_set.incomplete) { - return result; - } - // if the container set is the global one, it will always work. - if (type_is_global_error_set(container_set)) { - return result; - } - - if (!resolve_inferred_error_set(ira->codegen, contained_set, source_node)) { - result.id = ConstCastResultIdUnresolvedInferredErrSet; - return result; - } - - if (type_is_global_error_set(contained_set)) { - result.id = ConstCastResultIdErrSetGlobal; - return result; - } - - size_t errors_count = g->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - if (result.id == ConstCastResultIdOk) { - result.id = ConstCastResultIdErrSet; - result.data.error_set_mismatch = heap::c_allocator.create(); - } - result.data.error_set_mismatch->missing_errors.append(contained_error_entry); - } - } - heap::c_allocator.deallocate(errors, errors_count); - return result; - } - - // fn - if (wanted_type->id == ZigTypeIdFn && - actual_type->id == ZigTypeIdFn) - { - if (wanted_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) { - result.id = ConstCastResultIdFnAlign; - return result; - } - if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) { - result.id = ConstCastResultIdFnVarArgs; - return result; - } - if (wanted_type->data.fn.is_generic != actual_type->data.fn.is_generic) { - result.id = ConstCastResultIdFnIsGeneric; - return result; - } - if (!wanted_type->data.fn.is_generic && - actual_type->data.fn.fn_type_id.return_type->id != ZigTypeIdUnreachable) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type, - actual_type->data.fn.fn_type_id.return_type, source_node, false); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdFnReturnType; - result.data.return_type = heap::c_allocator.allocate_nonzero(1); - *result.data.return_type = child; - return result; - } - } - if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) { - result.id = ConstCastResultIdFnArgCount; - return result; - } - if (wanted_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) { - result.id = ConstCastResultIdFnGenericArgCount; - return result; - } - assert(wanted_type->data.fn.is_generic || - wanted_type->data.fn.fn_type_id.next_param_index == wanted_type->data.fn.fn_type_id.param_count); - for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.param_count; i += 1) { - // note it's reversed for parameters - FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i]; - FnTypeParamInfo *expected_param_info = &wanted_type->data.fn.fn_type_id.param_info[i]; - - ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, - expected_param_info->type, source_node, false); - if (arg_child.id == ConstCastResultIdInvalid) - return arg_child; - if (arg_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdFnArg; - result.data.fn_arg.arg_index = i; - result.data.fn_arg.actual_param_type = actual_param_info->type; - result.data.fn_arg.expected_param_type = expected_param_info->type; - result.data.fn_arg.child = heap::c_allocator.allocate_nonzero(1); - *result.data.fn_arg.child = arg_child; - return result; - } - - if (expected_param_info->is_noalias != actual_param_info->is_noalias) { - result.id = ConstCastResultIdFnArgNoAlias; - result.data.arg_no_alias.arg_index = i; - return result; - } - } - if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) { - // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. - result.id = ConstCastResultIdFnCC; - return result; - } - return result; - } - - if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt) { - if (wanted_type->data.integral.is_signed != actual_type->data.integral.is_signed || - wanted_type->data.integral.bit_count != actual_type->data.integral.bit_count) - { - result.id = ConstCastResultIdIntShorten; - result.data.int_shorten = heap::c_allocator.allocate_nonzero(1); - result.data.int_shorten->wanted_type = wanted_type; - result.data.int_shorten->actual_type = actual_type; - return result; - } - return result; - } - - if (wanted_type->id == ZigTypeIdFloat && actual_type->id == ZigTypeIdFloat) { - if (wanted_type->data.floating.bit_count == actual_type->data.floating.bit_count) { - return result; - } - } - - if (wanted_type->id == ZigTypeIdVector && actual_type->id == ZigTypeIdVector) { - if (actual_type->data.vector.len != wanted_type->data.vector.len) { - result.id = ConstCastResultIdVectorLength; - return result; - } - - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.vector.elem_type, - actual_type->data.vector.elem_type, source_node, false); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdVectorChild; - return result; - } - - return result; - } - - result.id = ConstCastResultIdType; - result.data.type_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.type_mismatch->wanted_type = wanted_type; - result.data.type_mismatch->actual_type = actual_type; - return result; -} - -static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) { - size_t old_errors_count = *errors_count; - *errors_count = g->errors_by_index.length; - *errors = heap::c_allocator.reallocate(*errors, old_errors_count, *errors_count); -} - -static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, - Stage1AirInst **instructions, size_t instruction_count) -{ - Error err; - assert(instruction_count >= 1); - Stage1AirInst *prev_inst; - size_t i = 0; - for (;;) { - prev_inst = instructions[i]; - if (type_is_invalid(prev_inst->value->type)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (prev_inst->value->type->id == ZigTypeIdUnreachable) { - i += 1; - if (i == instruction_count) { - return prev_inst->value->type; - } - continue; - } - break; - } - ErrorTableEntry **errors = nullptr; - size_t errors_count = 0; - ZigType *err_set_type = nullptr; - if (prev_inst->value->type->id == ZigTypeIdErrorSet) { - if (!resolve_inferred_error_set(ira->codegen, prev_inst->value->type, prev_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_global_error_set(prev_inst->value->type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - } else { - err_set_type = prev_inst->value->type; - update_errors_helper(ira->codegen, &errors, &errors_count); - - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - } - } - - bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull); - bool convert_to_const_slice = false; - bool make_the_slice_const = false; - bool make_the_pointer_const = false; - for (; i < instruction_count; i += 1) { - Stage1AirInst *cur_inst = instructions[i]; - ZigType *cur_type = cur_inst->value->type; - ZigType *prev_type = prev_inst->value->type; - - if (type_is_invalid(cur_type)) { - return cur_type; - } - - if (prev_type == cur_type) { - continue; - } - - if (prev_type->id == ZigTypeIdUnreachable) { - prev_inst = cur_inst; - continue; - } - - if (cur_type->id == ZigTypeIdUnreachable) { - continue; - } - - if (prev_type->id == ZigTypeIdErrorSet) { - ir_assert(err_set_type != nullptr, prev_inst); - if (cur_type->id == ZigTypeIdErrorSet) { - if (type_is_global_error_set(err_set_type)) { - continue; - } - bool allow_infer = cur_type->data.error_set.infer_fn != nullptr && - cur_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - // number of declared errors might have increased now - update_errors_helper(ira->codegen, &errors, &errors_count); - - // if err_set_type is a superset of cur_type, keep err_set_type. - // if cur_type is a superset of err_set_type, switch err_set_type to cur_type - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - - // unset everything in errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_type; - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } - - // neither of them are supersets. so we invent a new error set type that is a union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type, nullptr); - assert(errors != nullptr); - continue; - } else if (cur_type->id == ZigTypeIdErrorUnion) { - if (type_is_global_error_set(err_set_type)) { - prev_inst = cur_inst; - continue; - } - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - bool allow_infer = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_err_set_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - // test if err_set_type is a subset of cur_type's error set - // unset everything in errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_err_set_type; - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } - - // not a subset. invent new error set type, union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type, nullptr); - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } else { - prev_inst = cur_inst; - continue; - } - } - - if (cur_type->id == ZigTypeIdErrorSet) { - bool allow_infer = cur_type->data.error_set.infer_fn != nullptr && - cur_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - if (err_set_type == nullptr) { - bool allow_infer = false; - if (prev_type->id == ZigTypeIdErrorUnion) { - err_set_type = prev_type->data.error_union.err_set_type; - allow_infer = err_set_type->data.error_set.infer_fn != nullptr && - err_set_type->data.error_set.infer_fn == ira->fn; - } else { - err_set_type = cur_type; - } - - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if (!allow_infer && type_is_global_error_set(err_set_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - if (err_set_type == cur_type) { - continue; - } - } - // check if the cur type error set is a subset - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - // not a subset. invent new error set type, union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type, nullptr); - assert(errors != nullptr); - continue; - } - - if (prev_type->id == ZigTypeIdErrorUnion && cur_type->id == ZigTypeIdErrorUnion) { - ZigType *prev_payload_type = prev_type->data.error_union.payload_type; - ZigType *cur_payload_type = cur_type->data.error_union.payload_type; - - bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type, - source_node, false).id == ConstCastResultIdOk; - bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type, - source_node, false).id == ConstCastResultIdOk; - - if (const_cast_prev || const_cast_cur) { - if (const_cast_cur) { - prev_inst = cur_inst; - } - - ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type; - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - if (prev_err_set_type == cur_err_set_type) - continue; - - bool allow_infer_prev = prev_err_set_type->data.error_set.infer_fn != nullptr && - prev_err_set_type->data.error_set.infer_fn == ira->fn; - bool allow_infer_cur = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - - if (!allow_infer_prev && !resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if (!allow_infer_cur && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if ((!allow_infer_prev && type_is_global_error_set(prev_err_set_type)) || - (!allow_infer_cur && type_is_global_error_set(cur_err_set_type))) - { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - if (err_set_type == nullptr) { - err_set_type = prev_err_set_type; - for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - } - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - // unset all the errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = prev_err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_err_set_type; - continue; - } - - err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, prev_err_set_type, nullptr); - continue; - } - } - - if (prev_type->id == ZigTypeIdNull) { - prev_inst = cur_inst; - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdNull) { - any_are_null = true; - continue; - } - - if (prev_type->id == ZigTypeIdEnum && cur_type->id == ZigTypeIdEnumLiteral) { - TypeEnumField *field = find_enum_type_field(prev_type, cur_inst->value->data.x_enum_literal); - if (field != nullptr) { - continue; - } - } - if (is_tagged_union(prev_type) && cur_type->id == ZigTypeIdEnumLiteral) { - TypeUnionField *field = find_union_type_field(prev_type, cur_inst->value->data.x_enum_literal); - if (field != nullptr) { - continue; - } - } - - if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdEnumLiteral) { - TypeEnumField *field = find_enum_type_field(cur_type, prev_inst->value->data.x_enum_literal); - if (field != nullptr) { - prev_inst = cur_inst; - continue; - } - } - - if (is_tagged_union(cur_type) && prev_type->id == ZigTypeIdEnumLiteral) { - TypeUnionField *field = find_union_type_field(cur_type, prev_inst->value->data.x_enum_literal); - if (field != nullptr) { - prev_inst = cur_inst; - continue; - } - } - - if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC && - (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt)) - { - continue; - } - - if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC && - (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt)) - { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdPointer && cur_type->id == ZigTypeIdPointer) { - if (prev_type->data.pointer.ptr_len == PtrLenC && - types_match_const_cast_only(ira, prev_type->data.pointer.child_type, - cur_type->data.pointer.child_type, source_node, - !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - continue; - } - if (cur_type->data.pointer.ptr_len == PtrLenC && - types_match_const_cast_only(ira, cur_type->data.pointer.child_type, - prev_type->data.pointer.child_type, source_node, - !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - continue; - } - } - - if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { - continue; - } - - if (types_match_const_cast_only(ira, cur_type, prev_type, source_node, false).id == ConstCastResultIdOk) { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdInt && - cur_type->id == ZigTypeIdInt) - { - if ((prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) || - (cur_type->data.integral.is_signed && !prev_type->data.integral.is_signed)) { - if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) { - prev_inst = cur_inst; - } - } - continue; - } - - if (prev_type->id == ZigTypeIdFloat && cur_type->id == ZigTypeIdFloat) { - if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) { - prev_inst = cur_inst; - } - continue; - } - - if (prev_type->id == ZigTypeIdErrorUnion && - types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, - source_node, false).id == ConstCastResultIdOk) - { - continue; - } - - if (cur_type->id == ZigTypeIdErrorUnion && - types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, - source_node, false).id == ConstCastResultIdOk) - { - if (err_set_type != nullptr) { - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - bool allow_infer = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if ((!allow_infer && type_is_global_error_set(cur_err_set_type)) || - type_is_global_error_set(err_set_type)) - { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type, nullptr); - } - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, - source_node, false).id == ConstCastResultIdOk) - { - continue; - } - - if (cur_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, - source_node, false).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, cur_type, prev_type->data.maybe.child_type, - source_node, false).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, prev_type, cur_type->data.maybe.child_type, - source_node, false).id == ConstCastResultIdOk) - { - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdUndefined) { - continue; - } - - if (prev_type->id == ZigTypeIdUndefined) { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdComptimeInt || - prev_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) { - prev_inst = cur_inst; - continue; - } else { - return ira->codegen->builtin_types.entry_invalid; - } - } - - if (cur_type->id == ZigTypeIdComptimeInt || - cur_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) { - continue; - } else { - return ira->codegen->builtin_types.entry_invalid; - } - } - - // *[N]T to [*]T - if (prev_type->id == ZigTypeIdPointer && - prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) - { - convert_to_const_slice = false; - prev_inst = cur_inst; - - if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) { - // const array pointer and non-const unknown pointer - make_the_pointer_const = true; - } - continue; - } - - // *[N]T to [*]T - if (cur_type->id == ZigTypeIdPointer && - cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) - { - if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) { - // const array pointer and non-const unknown pointer - make_the_pointer_const = true; - } - continue; - } - - // *[N]T to []T - // *[N]T to E![]T - if (cur_type->id == ZigTypeIdPointer && - cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ((prev_type->id == ZigTypeIdErrorUnion && is_slice(prev_type->data.error_union.payload_type)) || - is_slice(prev_type))) - { - ZigType *array_type = cur_type->data.pointer.child_type; - ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ? - prev_type->data.error_union.payload_type : prev_type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) - { - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !cur_type->data.pointer.is_const); - if (!const_ok) make_the_slice_const = true; - convert_to_const_slice = false; - continue; - } - } - - // *[N]T to []T - // *[N]T to E![]T - if (prev_type->id == ZigTypeIdPointer && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - prev_type->data.pointer.ptr_len == PtrLenSingle && - ((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) || - (cur_type->id == ZigTypeIdOptional && is_slice(cur_type->data.maybe.child_type)) || - is_slice(cur_type))) - { - ZigType *array_type = prev_type->data.pointer.child_type; - ZigType *slice_type; - switch (cur_type->id) { - case ZigTypeIdErrorUnion: - slice_type = cur_type->data.error_union.payload_type; - break; - case ZigTypeIdOptional: - slice_type = cur_type->data.maybe.child_type; - break; - default: - slice_type = cur_type; - break; - } - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) - { - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !prev_type->data.pointer.is_const); - if (!const_ok) make_the_slice_const = true; - prev_inst = cur_inst; - convert_to_const_slice = false; - continue; - } - } - - // *[N]T and *[M]T - if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - ( - prev_type->data.pointer.child_type->data.array.sentinel == nullptr || - (cur_type->data.pointer.child_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, prev_type->data.pointer.child_type->data.array.sentinel, - cur_type->data.pointer.child_type->data.array.sentinel)) - ) && - types_match_const_cast_only(ira, - cur_type->data.pointer.child_type->data.array.child_type, - prev_type->data.pointer.child_type->data.array.child_type, - source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool const_ok = (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const || - prev_type->data.pointer.child_type->data.array.len == 0); - if (!const_ok) make_the_slice_const = true; - prev_inst = cur_inst; - convert_to_const_slice = true; - continue; - } - if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ( - cur_type->data.pointer.child_type->data.array.sentinel == nullptr || - (prev_type->data.pointer.child_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, cur_type->data.pointer.child_type->data.array.sentinel, - prev_type->data.pointer.child_type->data.array.sentinel)) - ) && - types_match_const_cast_only(ira, - prev_type->data.pointer.child_type->data.array.child_type, - cur_type->data.pointer.child_type->data.array.child_type, - source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool const_ok = (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const || - cur_type->data.pointer.child_type->data.array.len == 0); - if (!const_ok) make_the_slice_const = true; - convert_to_const_slice = true; - continue; - } - - if (prev_type->id == ZigTypeIdEnum && is_tagged_union(cur_type)) { - if ((err = type_resolve(ira->codegen, cur_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->builtin_types.entry_invalid; - if (cur_type->data.unionation.tag_type == prev_type) { - continue; - } - } - - if (cur_type->id == ZigTypeIdEnum && is_tagged_union(prev_type)) { - if ((err = type_resolve(ira->codegen, prev_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->builtin_types.entry_invalid; - if (prev_type->data.unionation.tag_type == cur_type) { - prev_inst = cur_inst; - continue; - } - } - - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("incompatible types: '%s' and '%s'", - buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); - add_error_note(ira->codegen, msg, prev_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); - add_error_note(ira->codegen, msg, cur_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); - - return ira->codegen->builtin_types.entry_invalid; - } - - heap::c_allocator.deallocate(errors, errors_count); - - if (convert_to_const_slice) { - if (prev_inst->value->type->id == ZigTypeIdPointer) { - ZigType *array_type = prev_inst->value->type->data.pointer.child_type; - src_assert(array_type->id == ZigTypeIdArray, source_node); - ZigType *ptr_type = get_pointer_to_type_extra2( - ira->codegen, array_type->data.array.child_type, - prev_inst->value->type->data.pointer.is_const || make_the_slice_const, false, - PtrLenUnknown, - 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel); - ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); - if (err_set_type != nullptr) { - return get_error_union_type(ira->codegen, err_set_type, slice_type); - } else { - return slice_type; - } - } else { - zig_unreachable(); - } - } else if (err_set_type != nullptr) { - if (prev_inst->value->type->id == ZigTypeIdErrorSet) { - return err_set_type; - } else if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = prev_inst->value->type->data.error_union.payload_type; - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } else if (expected_type != nullptr && expected_type->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = expected_type->data.error_union.payload_type; - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } else { - if (prev_inst->value->type->id == ZigTypeIdComptimeInt || - prev_inst->value->type->id == ZigTypeIdComptimeFloat) - { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to make error union out of number literal")); - return ira->codegen->builtin_types.entry_invalid; - } else if (prev_inst->value->type->id == ZigTypeIdNull) { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to make error union out of null literal")); - return ira->codegen->builtin_types.entry_invalid; - } else { - if ((err = type_resolve(ira->codegen, prev_inst->value->type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, prev_inst->value->type); - } - } - } else if (any_are_null && prev_inst->value->type->id != ZigTypeIdNull) { - if (prev_inst->value->type->id == ZigTypeIdOptional) { - return prev_inst->value->type; - } else { - if ((err = type_resolve(ira->codegen, prev_inst->value->type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_optional_type(ira->codegen, prev_inst->value->type); - } - } else if (make_the_slice_const) { - ZigType *slice_type; - if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - slice_type = prev_inst->value->type->data.error_union.payload_type; - } else if (is_slice(prev_inst->value->type)) { - slice_type = prev_inst->value->type; - } else { - zig_unreachable(); - } - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *adjusted_ptr_type = adjust_ptr_const(ira->codegen, slice_ptr_type, make_the_slice_const); - ZigType *adjusted_slice_type = get_slice_type(ira->codegen, adjusted_ptr_type); - if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - return get_error_union_type(ira->codegen, prev_inst->value->type->data.error_union.err_set_type, - adjusted_slice_type); - } else if (is_slice(prev_inst->value->type)) { - return adjusted_slice_type; - } else { - zig_unreachable(); - } - } else if (make_the_pointer_const) { - return adjust_ptr_const(ira->codegen, prev_inst->value->type, make_the_pointer_const); - } else { - return prev_inst->value->type; - } -} - -static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - CastOp cast_op, - ZigValue *other_val, ZigType *other_type, - ZigValue *const_val, ZigType *new_type) -{ - const_val->special = other_val->special; - - assert(other_val != const_val); - switch (cast_op) { - case CastOpNoCast: - zig_unreachable(); - case CastOpErrSet: - case CastOpBitCast: - zig_panic("TODO: eval_const_expr_implicit_cast CastOpErrSet, CastOpBitCast"); - case CastOpNoop: { - copy_const_val(ira->codegen, const_val, other_val); - const_val->type = new_type; - break; - } - case CastOpNumLitToConcrete: - if (other_val->type->id == ZigTypeIdComptimeFloat) { - assert(new_type->id == ZigTypeIdFloat); - switch (new_type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = bigfloat_to_f16(&other_val->data.x_bigfloat); - break; - case 32: - const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat); - break; - case 64: - const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat); - break; - case 80: { - float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); - f128M_to_extF80M(&tmp, &const_val->data.x_f80); - break; - } - case 128: - const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat); - break; - default: - zig_unreachable(); - } - } else if (other_val->type->id == ZigTypeIdComptimeInt) { - bigint_init_bigint(&const_val->data.x_bigint, &other_val->data.x_bigint); - } else { - zig_unreachable(); - } - const_val->type = new_type; - break; - case CastOpIntToFloat: - if (new_type->id == ZigTypeIdFloat) { - BigFloat bigfloat; - bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint); - switch (new_type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = bigfloat_to_f16(&bigfloat); - break; - case 32: - const_val->data.x_f32 = bigfloat_to_f32(&bigfloat); - break; - case 64: - const_val->data.x_f64 = bigfloat_to_f64(&bigfloat); - break; - case 80: { - float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); - f128M_to_extF80M(&tmp, &const_val->data.x_f80); - break; - } - case 128: - const_val->data.x_f128 = bigfloat_to_f128(&bigfloat); - break; - default: - zig_unreachable(); - } - } else if (new_type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_bigint(&const_val->data.x_bigfloat, &other_val->data.x_bigint); - } else { - zig_unreachable(); - } - const_val->special = ConstValSpecialStatic; - break; - case CastOpFloatToInt: - float_init_bigint(&const_val->data.x_bigint, other_val); - if (new_type->id == ZigTypeIdInt) { - if (!bigint_fits_in_bits(&const_val->data.x_bigint, new_type->data.integral.bit_count, - new_type->data.integral.is_signed)) - { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &const_val->data.x_bigint, 10); - - ir_add_error_node(ira, source_node, - buf_sprintf("integer value '%s' cannot be stored in type '%s'", - buf_ptr(int_buf), buf_ptr(&new_type->name))); - return false; - } - } - - const_val->special = ConstValSpecialStatic; - break; - case CastOpBoolToInt: - bigint_init_unsigned(&const_val->data.x_bigint, other_val->data.x_bool ? 1 : 0); - const_val->special = ConstValSpecialStatic; - break; - } - return true; -} - -static Stage1AirInst *ir_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - Stage1AirInst *new_instruction = &const_instruction->base; - new_instruction->value->type = ty; - new_instruction->value->special = ConstValSpecialStatic; - ira->new_irb.constants.append(&heap::c_allocator, const_instruction); - return new_instruction; -} - -static Stage1AirInst *ir_const_noval(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstConst *const_instruction = ir_create_inst_noval(&ira->new_irb, - scope, source_node); - ira->new_irb.constants.append(&heap::c_allocator, const_instruction); - return &const_instruction->base; -} - -// This function initializes the new Stage1AirInst with the provided ZigValue, -// rather than creating a new one. -static Stage1AirInst *ir_const_move(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigValue *val) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = val; - return result; -} - -static Stage1AirInst *ir_resolve_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type, CastOp cast_op) -{ - if (instr_is_comptime(value) || !type_has_bits(ira->codegen, wanted_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!eval_const_expr_implicit_cast(ira, scope, source_node, cast_op, val, val->type, - result->value, wanted_type)) - { - return ira->codegen->invalid_inst_gen; - } - return result; - } else { - return ir_build_cast(ira, scope, source_node, - wanted_type, value, cast_op); - } -} - -static Stage1AirInst *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, - Scope *scope, AstNode *source_node, Stage1AirInst *value, ZigType *wanted_type) -{ - src_assert(value->value->type->id == ZigTypeIdPointer, source_node); - - Error err; - - if ((err = type_resolve(ira->codegen, value->value->type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value->type)); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, wanted_type); - - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->data.x_ptr.special = ConstPtrSpecialBaseArray; - result->value->data.x_ptr.mut = val->data.x_ptr.mut; - result->value->data.x_ptr.data.base_array.array_val = pointee; - result->value->data.x_ptr.data.base_array.elem_index = 0; - return result; - } - } - - return ir_build_cast(ira, scope, source_node, - wanted_type, value, CastOpBitCast); -} - -static Stage1AirInst *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array_ptr, ZigType *wanted_type, ResultLoc *result_loc) -{ - Error err; - - assert(array_ptr->value->type->id == ZigTypeIdPointer); - assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); - - ZigType *array_type = array_ptr->value->type->data.pointer.child_type; - size_t array_len = array_type->data.array.len; - - // A zero-sized array can be casted regardless of the destination alignment, or - // whether the pointer is undefined, and the result is always comptime known. - // TODO However, this is exposing a result location bug that I failed to solve on the first try. - // If you want to try to fix the bug, uncomment this block and get the tests passing. - //if (array_len == 0 && array_type->data.array.sentinel == nullptr) { - // ZigValue *undef_array = ira->codegen->pass1_arena->create(); - // undef_array->special = ConstValSpecialUndef; - // undef_array->type = array_type; - - // Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false, nullptr); - // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; - // result->value->type = wanted_type; - // return result; - //} - - if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if (array_len != 0) { - wanted_type = adjust_slice_align(ira->codegen, wanted_type, - get_ptr_align(ira->codegen, array_ptr->value->type)); - } - - if (instr_is_comptime(array_ptr)) { - UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad; - ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed); - if (array_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - src_assert(is_slice(wanted_type), source_node); - if (array_ptr_val->special == ConstValSpecialUndef) { - ZigValue *undef_array = ira->codegen->pass1_arena->create(); - undef_array->special = ConstValSpecialUndef; - undef_array->type = array_type; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->value->type = wanted_type; - return result; - } - bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; - // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee - if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { - ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; - if (array_val->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, array_val, - array_ptr_val->data.x_ptr.data.base_array.elem_index, - array_type->data.array.len, wanted_const, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - result->value->type = wanted_type; - return result; - } - } else if (array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - assert(array_ptr_val->type->id == ZigTypeIdPointer); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - result->value->type = wanted_type; - return result; - } - } - } - - if (result_loc == nullptr) result_loc = no_result_loc(); - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, - result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - return ir_build_ptr_of_array_to_slice(ira, scope, source_node, wanted_type, array_ptr, result_loc_inst); -} - -static Stage1AirBasicBlock *ir_get_new_bb(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirInst *ref_old_instruction) { - assert(old_bb); - - if (old_bb->child) { - if (ref_old_instruction == nullptr || old_bb->child->ref_instruction != ref_old_instruction) { - return old_bb->child; - } - } - - Stage1AirBasicBlock *new_bb = ir_build_bb_from(ira, old_bb); - new_bb->ref_instruction = ref_old_instruction; - - return new_bb; -} - -static Stage1AirBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirInst *ref_old_instruction) { - assert(ref_old_instruction != nullptr); - Stage1AirBasicBlock *new_bb = ir_get_new_bb(ira, old_bb, ref_old_instruction); - if (new_bb->must_be_comptime_source_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, ref_old_instruction->source_node, - buf_sprintf("control flow attempts to use compile-time variable at runtime")); - add_error_note(ira->codegen, msg, new_bb->must_be_comptime_source_node, - buf_sprintf("compile-time variable assigned here")); - return nullptr; - } - return new_bb; -} - -static void ir_start_bb(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirBasicBlock *const_predecessor_bb) { - src_assert(!old_bb->suspended, - (old_bb->instruction_list.length != 0) ? - old_bb->instruction_list.at(0)->source_node : nullptr); - ira->instruction_index = 0; - ira->zir_current_basic_block = old_bb; - ira->const_predecessor_bb = const_predecessor_bb; - ira->old_bb_index = old_bb->index; -} - -static Stage1AirInst *ira_suspend(IrAnalyze *ira, Stage1ZirInst *old_instruction, Stage1ZirBasicBlock *next_bb, - IrSuspendPosition *suspend_pos) -{ - if (ira->codegen->verbose_ir) { - fprintf(stderr, "suspend %s_%" PRIu32 " %s_%" PRIu32 " #%" PRIu32 " (%zu,%zu)\n", - ira->zir_current_basic_block->name_hint, - ira->zir_current_basic_block->debug_id, - ira->zir->basic_block_list.at(ira->old_bb_index)->name_hint, - ira->zir->basic_block_list.at(ira->old_bb_index)->debug_id, - ira->zir_current_basic_block->instruction_list.at(ira->instruction_index)->debug_id, - ira->old_bb_index, ira->instruction_index); - } - suspend_pos->basic_block_index = ira->old_bb_index; - suspend_pos->instruction_index = ira->instruction_index; - - ira->zir_current_basic_block->suspended = true; - - // null next_bb means that the caller plans to call ira_resume before returning - if (next_bb != nullptr) { - ira->old_bb_index = next_bb->index; - ira->zir_current_basic_block = ira->zir->basic_block_list.at(ira->old_bb_index); - assert(ira->zir_current_basic_block == next_bb); - ira->instruction_index = 0; - ira->const_predecessor_bb = nullptr; - next_bb->child = ir_get_new_bb_runtime(ira, next_bb, old_instruction); - ira->new_irb.current_basic_block = next_bb->child; - } - return ira->codegen->unreach_instruction; -} - -static Stage1AirInst *ira_resume(IrAnalyze *ira) { - IrSuspendPosition pos = ira->resume_stack.pop(); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "resume (%zu,%zu) ", pos.basic_block_index, pos.instruction_index); - } - ira->old_bb_index = pos.basic_block_index; - ira->zir_current_basic_block = ira->zir->basic_block_list.at(ira->old_bb_index); - assert(ira->zir_current_basic_block->in_resume_stack); - ira->zir_current_basic_block->in_resume_stack = false; - ira->zir_current_basic_block->suspended = false; - ira->instruction_index = pos.instruction_index; - assert(pos.instruction_index < ira->zir_current_basic_block->instruction_list.length); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "%s_%" PRIu32 " #%" PRIu32 "\n", ira->zir_current_basic_block->name_hint, - ira->zir_current_basic_block->debug_id, - ira->zir_current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); - } - ira->const_predecessor_bb = nullptr; - ira->new_irb.current_basic_block = ira->zir_current_basic_block->child; - assert(ira->new_irb.current_basic_block != nullptr); - return ira->codegen->unreach_instruction; -} - -static void ir_start_next_bb(IrAnalyze *ira) { - ira->old_bb_index += 1; - - bool need_repeat = true; - for (;;) { - while (ira->old_bb_index < ira->zir->basic_block_list.length) { - Stage1ZirBasicBlock *old_bb = ira->zir->basic_block_list.at(ira->old_bb_index); - if (old_bb->child == nullptr && old_bb->suspend_instruction_ref == nullptr) { - ira->old_bb_index += 1; - continue; - } - // if it's already started, or - // if it's a suspended block, - // then skip it - if (old_bb->suspended || - (old_bb->child != nullptr && old_bb->child->instruction_list.length != 0) || - (old_bb->child != nullptr && old_bb->child->already_appended)) - { - ira->old_bb_index += 1; - continue; - } - - // if there is a resume_stack, pop one from there rather than moving on. - // the last item of the resume stack will be a basic block that will - // move on to the next one below - if (ira->resume_stack.length != 0) { - ira_resume(ira); - return; - } - - if (old_bb->child == nullptr) { - old_bb->child = ir_get_new_bb_runtime(ira, old_bb, old_bb->suspend_instruction_ref); - } - ira->new_irb.current_basic_block = old_bb->child; - ir_start_bb(ira, old_bb, nullptr); - return; - } - if (!need_repeat) { - if (ira->resume_stack.length != 0) { - ira_resume(ira); - } - return; - } - need_repeat = false; - ira->old_bb_index = 0; - continue; - } -} - -static void ir_finish_bb(IrAnalyze *ira) { - if (!ira->new_irb.current_basic_block->already_appended) { - ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "append new bb %s_%" PRIu32 "\n", ira->new_irb.current_basic_block->name_hint, - ira->new_irb.current_basic_block->debug_id); - } - } - ir_start_next_bb(ira); -} - -static Stage1AirInst *ir_unreach_error(IrAnalyze *ira) { - ira->old_bb_index = SIZE_MAX; - if (ira->new_irb.exec->first_err_trace_msg == nullptr) { - ira->new_irb.exec->first_err_trace_msg = ira->codegen->trace_err; - } - return ira->codegen->unreach_instruction; -} - -static bool ir_emit_backward_branch(IrAnalyze *ira, AstNode* source_node) { - size_t *bbc = ira->backward_branch_count; - size_t *quota = ira->backward_branch_quota; - - // If we're already over quota, we've already given an error message for this. - if (*bbc > *quota) { - assert(ira->codegen->errors.length > 0); - return false; - } - - *bbc += 1; - if (*bbc > *quota) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("evaluation exceeded %" ZIG_PRI_usize " backwards branches", *quota)); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("use @setEvalBranchQuota to raise branch limit from %" ZIG_PRI_usize, *quota)); - return false; - } - return true; -} - -static Stage1AirInst *ir_inline_bb(IrAnalyze *ira, AstNode* source_node, Stage1ZirBasicBlock *old_bb) { - if (old_bb->debug_id <= ira->zir_current_basic_block->debug_id) { - if (!ir_emit_backward_branch(ira, source_node)) - return ir_unreach_error(ira); - } - - old_bb->child = ira->zir_current_basic_block->child; - ir_start_bb(ira, old_bb, ira->zir_current_basic_block); - return ira->codegen->unreach_instruction; -} - -static Stage1AirInst *ir_finish_anal(IrAnalyze *ira, Stage1AirInst *instruction) { - if (instruction->value->type->id == ZigTypeIdUnreachable) - ir_finish_bb(ira); - return instruction; -} - -static Stage1AirInst *ir_const_fn(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigFn *fn_entry) { - Stage1AirInst *result = ir_const(ira, scope, source_node, fn_entry->type_entry); - result->value->special = ConstValSpecialStatic; - result->value->data.x_ptr.data.fn.fn_entry = fn_entry; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->value->data.x_ptr.special = ConstPtrSpecialFunction; - return result; -} - -static Stage1AirInst *ir_const_bound_fn(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1AirInst *first_arg, AstNode *first_arg_src) -{ - // This is unfortunately required to avoid improperly freeing first_arg_src - ira_ref(ira); - - Stage1AirInst *result = ir_const(ira, scope, source_node, get_bound_fn_type(ira->codegen, fn_entry)); - result->value->data.x_bound_fn.fn = fn_entry; - result->value->data.x_bound_fn.first_arg = first_arg; - result->value->data.x_bound_fn.first_arg_src = first_arg_src; - return result; -} - -static Stage1AirInst *ir_const_type(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_type); - result->value->data.x_type = ty; - return result; -} - -static Stage1AirInst *ir_const_bool(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool value) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - result->value->data.x_bool = value; - return result; -} - -static Stage1AirInst *ir_const_undef(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ty); - result->value->special = ConstValSpecialUndef; - return result; -} - -static Stage1AirInst *ir_const_unreachable(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = ira->codegen->intern.for_unreachable(); - return result; -} - -static Stage1AirInst *ir_const_void(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = ira->codegen->intern.for_void(); - return result; -} - -static Stage1AirInst *ir_const_unsigned(IrAnalyze *ira, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_num_lit_int); - bigint_init_unsigned(&result->value->data.x_bigint, value); - return result; -} - -static Stage1AirInst *ir_get_const_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *pointee, ZigType *pointee_type, - ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align) -{ - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type, - ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0, false); - Stage1AirInst *const_instr = ir_const(ira, scope, source_node, ptr_type); - ZigValue *const_val = const_instr->value; - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.mut = ptr_mut; - const_val->data.x_ptr.data.ref.pointee = pointee; - return const_instr; -} - -static Error ir_resolve_const_val(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *val, UndefAllowed undef_allowed) -{ - Error err; - for (;;) { - switch (val->special) { - case ConstValSpecialStatic: - return ErrorNone; - case ConstValSpecialRuntime: - if (!type_has_bits(codegen, val->type)) - return ErrorNone; - - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("unable to evaluate constant expression")); - return ErrorSemanticAnalyzeFail; - case ConstValSpecialUndef: - if (undef_allowed == UndefOk || undef_allowed == LazyOk) - return ErrorNone; - - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("use of undefined value here causes undefined behavior")); - return ErrorSemanticAnalyzeFail; - case ConstValSpecialLazy: - if (undef_allowed == LazyOk || undef_allowed == LazyOkNoUndef) - return ErrorNone; - - if ((err = ir_resolve_lazy(codegen, source_node, val))) - return err; - - continue; - } - } -} - -static ZigValue *ir_resolve_const(IrAnalyze *ira, Stage1AirInst *value, UndefAllowed undef_allowed) { - Error err; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node, - value->value, undef_allowed))) - { - return nullptr; - } - return value->value; -} - -Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigValue *return_ptr, size_t *backward_branch_count, size_t *backward_branch_quota, - ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - Stage1Air *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef_allowed) -{ - Error err; - - src_assert(return_ptr->type->id == ZigTypeIdPointer, source_node); - - if (type_is_invalid(return_ptr->type)) - return ErrorSemanticAnalyzeFail; - - Stage1Zir *stage1_zir = heap::c_allocator.create(); - stage1_zir->name = exec_name; - stage1_zir->is_inline = true; - stage1_zir->begin_scope = scope; - - bool in_c_import_scope = c_import_buf != nullptr; - - if (!stage1_astgen(codegen, node, scope, stage1_zir, fn_entry, in_c_import_scope)) - return ErrorSemanticAnalyzeFail; - - if (stage1_zir->first_err_trace_msg != nullptr) { - codegen->trace_err = stage1_zir->first_err_trace_msg; - return ErrorSemanticAnalyzeFail; - } - - if (codegen->verbose_ir) { - fprintf(stderr, "\n{ // (IR)\n"); - ir_print_src(codegen, stderr, stage1_zir, 2); - fprintf(stderr, "}\n"); - } - Stage1Air *analyzed_executable = heap::c_allocator.create(); - analyzed_executable->source_node = source_node; - analyzed_executable->parent_exec = parent_exec; - analyzed_executable->source_exec = stage1_zir; - analyzed_executable->name = exec_name; - analyzed_executable->is_inline = true; - analyzed_executable->c_import_buf = c_import_buf; - analyzed_executable->begin_scope = scope; - ZigType *result_type = ir_analyze(codegen, stage1_zir, analyzed_executable, - backward_branch_count, backward_branch_quota, - return_ptr->type->data.pointer.child_type, expected_type_source_node, return_ptr, - fn_entry); - if (type_is_invalid(result_type)) { - return ErrorSemanticAnalyzeFail; - } - - if (codegen->verbose_ir) { - fprintf(stderr, "{ // (analyzed)\n"); - ir_print_gen(codegen, stderr, analyzed_executable, 2); - fprintf(stderr, "}\n"); - } - - if ((err = ir_exec_scan_for_side_effects(codegen, analyzed_executable))) - return err; - - ZigValue *result = const_ptr_pointee(nullptr, codegen, return_ptr, source_node); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - if ((err = ir_resolve_const_val(codegen, analyzed_executable, node, result, undef_allowed))) - return err; - - return ErrorNone; -} - -static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, Stage1AirInst *err_value) { - if (type_is_invalid(err_value->value->type)) - return nullptr; - - if (err_value->value->type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, err_value->source_node, - buf_sprintf("expected error, found '%s'", buf_ptr(&err_value->value->type->name))); - return nullptr; - } - - ZigValue *const_val = ir_resolve_const(ira, err_value, UndefBad); - if (!const_val) - return nullptr; - - assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set; -} - -static ZigType *ir_resolve_const_type(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *val) -{ - Error err; - if ((err = ir_resolve_const_val(codegen, exec, source_node, val, UndefBad))) - return codegen->builtin_types.entry_invalid; - - assert(val->data.x_type != nullptr); - return val->data.x_type; -} - -static ZigValue *ir_resolve_type_lazy(IrAnalyze *ira, Stage1AirInst *type_value) { - if (type_is_invalid(type_value->value->type)) - return nullptr; - - if (type_value->value->type->id != ZigTypeIdMetaType) { - ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value->type->name))); - return nullptr; - } - - Error err; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, type_value->source_node, - type_value->value, LazyOkNoUndef))) - { - return nullptr; - } - - return type_value->value; -} - -static ZigType *ir_resolve_type(IrAnalyze *ira, Stage1AirInst *type_value) { - ZigValue *val = ir_resolve_type_lazy(ira, type_value); - if (val == nullptr) - return ira->codegen->builtin_types.entry_invalid; - - return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); -} - -static Error ir_validate_vector_elem_type(IrAnalyze *ira, AstNode *source_node, ZigType *elem_type) { - Error err; - bool is_valid; - if ((err = is_valid_vector_elem_type(ira->codegen, elem_type, &is_valid))) - return err; - if (!is_valid) { - ir_add_error_node(ira, source_node, - buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - } - return ErrorNone; -} - -static ZigType *ir_resolve_vector_elem_type(IrAnalyze *ira, Stage1AirInst *elem_type_value) { - Error err; - ZigType *elem_type = ir_resolve_type(ira, elem_type_value); - if (type_is_invalid(elem_type)) - return ira->codegen->builtin_types.entry_invalid; - if ((err = ir_validate_vector_elem_type(ira, elem_type_value->source_node, elem_type))) - return ira->codegen->builtin_types.entry_invalid; - return elem_type; -} - -static ZigType *ir_resolve_int_type(IrAnalyze *ira, Stage1AirInst *type_value) { - ZigType *ty = ir_resolve_type(ira, type_value); - if (type_is_invalid(ty)) - return ira->codegen->builtin_types.entry_invalid; - - if (ty->id != ZigTypeIdInt) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); - if (ty->id == ZigTypeIdVector && - ty->data.vector.elem_type->id == ZigTypeIdInt) - { - add_error_note(ira->codegen, msg, type_value->source_node, - buf_sprintf("represent vectors with their element types, i.e. '%s'", - buf_ptr(&ty->data.vector.elem_type->name))); - } - return ira->codegen->builtin_types.entry_invalid; - } - - return ty; -} - -static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, AstNode *op_source, Stage1AirInst *type_value) { - if (type_is_invalid(type_value->value->type)) - return ira->codegen->builtin_types.entry_invalid; - - if (type_value->value->type->id != ZigTypeIdMetaType) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value->type->name))); - add_error_note(ira->codegen, msg, op_source, - buf_sprintf("`||` merges error sets; `or` performs boolean OR")); - return ira->codegen->builtin_types.entry_invalid; - } - - ZigValue *const_val = ir_resolve_const(ira, type_value, UndefBad); - if (!const_val) - return ira->codegen->builtin_types.entry_invalid; - - assert(const_val->data.x_type != nullptr); - ZigType *result_type = const_val->data.x_type; - if (result_type->id != ZigTypeIdErrorSet) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name))); - add_error_note(ira->codegen, msg, op_source, - buf_sprintf("`||` merges error sets; `or` performs boolean OR")); - return ira->codegen->builtin_types.entry_invalid; - } - return result_type; -} - -static ZigFn *ir_resolve_fn(IrAnalyze *ira, Stage1AirInst *fn_value) { - if (type_is_invalid(fn_value->value->type)) - return nullptr; - - if (fn_value->value->type->id != ZigTypeIdFn) { - ir_add_error_node(ira, fn_value->source_node, - buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->value->type->name))); - return nullptr; - } - - ZigValue *const_val = ir_resolve_const(ira, fn_value, UndefBad); - if (!const_val) - return nullptr; - - // May be a ConstPtrSpecialHardCodedAddr - if (const_val->data.x_ptr.special != ConstPtrSpecialFunction) - return nullptr; - - return const_val->data.x_ptr.data.fn.fn_entry; -} - -static Stage1AirInst *ir_analyze_optional_wrap(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdOptional); - - if (instr_is_comptime(value)) { - ZigType *payload_type = wanted_type->data.maybe.child_type; - Stage1AirInst *casted_payload = ir_implicit_cast(ira, value, payload_type); - if (type_is_invalid(casted_payload->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *val = ir_resolve_const(ira, casted_payload, UndefOk); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->special = ConstValSpecialStatic; - if (types_have_same_zig_comptime_repr(ira->codegen, wanted_type, payload_type)) { - copy_const_val(ira->codegen, const_instruction->base.value, val); - } else { - const_instruction->base.value->data.x_optional = val; - } - const_instruction->base.value->type = wanted_type; - return &const_instruction->base; - } - - if (result_loc == nullptr && handle_is_ptr(ira->codegen, wanted_type)) { - result_loc = no_result_loc(); - } - Stage1AirInst *result_loc_inst = nullptr; - if (result_loc != nullptr) { - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - } - Stage1AirInst *result = ir_build_optional_wrap(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_maybe = RuntimeHintOptionalNonNull; - return result; -} - -static Stage1AirInst *ir_analyze_err_wrap_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdErrorUnion); - - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; - if (instr_is_comptime(value)) { - Stage1AirInst *casted_payload = ir_implicit_cast(ira, value, payload_type); - if (type_is_invalid(casted_payload->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *val = ir_resolve_const(ira, casted_payload, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *err_set_val = ira->codegen->pass1_arena->create(); - err_set_val->type = err_set_type; - err_set_val->special = ConstValSpecialStatic; - err_set_val->data.x_err_set = nullptr; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_union.error_set = err_set_val; - const_instruction->base.value->data.x_err_union.payload = val; - return &const_instruction->base; - } - - Stage1AirInst *result_loc_inst; - if (handle_is_ptr(ira->codegen, wanted_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - Stage1AirInst *result = ir_build_err_wrap_payload(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_error_union = RuntimeHintErrorUnionNonError; - return result; -} - -static Stage1AirInst *ir_analyze_err_set_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type) -{ - assert(value->value->type->id == ZigTypeIdErrorSet); - assert(wanted_type->id == ZigTypeIdErrorSet); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (!type_is_global_error_set(wanted_type)) { - bool subset = false; - for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { - if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) { - subset = true; - break; - } - } - if (!subset) { - ir_add_error_node(ira, source_node, - buf_sprintf("error.%s not a member of error set '%s'", - buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_set = val->data.x_err_set; - return &const_instruction->base; - } - - return ir_build_cast(ira, scope, source_node, wanted_type, value, CastOpErrSet); -} - -static Stage1AirInst *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame_ptr, ZigType *wanted_type) -{ - if (instr_is_comptime(frame_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, frame_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - src_assert(ptr_val->type->id == ZigTypeIdPointer, source_node ); - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - zig_panic("TODO comptime frame pointer"); - } - } - - return ir_build_cast(ira, scope, source_node, wanted_type, frame_ptr, CastOpBitCast); -} - -static Stage1AirInst *ir_analyze_anyframe_to_anyframe(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type) -{ - if (instr_is_comptime(value)) { - zig_panic("TODO comptime anyframe->T to anyframe"); - } - - return ir_build_cast(ira, scope, source_node, wanted_type, value, CastOpBitCast); -} - - -static Stage1AirInst *ir_analyze_err_wrap_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdErrorUnion); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - ZigValue *err_set_val = ira->codegen->pass1_arena->create(); - err_set_val->special = ConstValSpecialStatic; - err_set_val->type = wanted_type->data.error_union.err_set_type; - err_set_val->data.x_err_set = val->data.x_err_set; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_union.error_set = err_set_val; - const_instruction->base.value->data.x_err_union.payload = nullptr; - return &const_instruction->base; - } - - Stage1AirInst *result_loc_inst; - if (handle_is_ptr(ira->codegen, wanted_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - - Stage1AirInst *result = ir_build_err_wrap_code(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_error_union = RuntimeHintErrorUnionError; - return result; -} - -static Stage1AirInst *ir_analyze_null_to_maybe(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, ZigType *wanted_type) { - assert(wanted_type->id == ZigTypeIdOptional); - assert(instr_is_comptime(value)); - - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - assert(val != nullptr); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - - if (get_src_ptr_type(wanted_type) != nullptr) { - result->value->data.x_ptr.special = ConstPtrSpecialNull; - } else if (is_opt_err_set(wanted_type)) { - result->value->data.x_err_set = nullptr; - } else { - result->value->data.x_optional = nullptr; - } - return result; -} - -static Stage1AirInst *ir_analyze_null_to_c_pointer(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdPointer); - assert(wanted_type->data.pointer.ptr_len == PtrLenC); - assert(instr_is_comptime(value)); - - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - assert(val != nullptr); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->data.x_ptr.special = ConstPtrSpecialNull; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - return result; -} - -static Stage1AirInst *ir_get_ref2(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *elem_type, bool is_const, bool is_volatile) -{ - Error err; - - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, LazyOk); - if (!val) - return ira->codegen->invalid_inst_gen; - return ir_get_const_ptr(ira, scope, source_node, val, elem_type, - ConstPtrMutComptimeConst, is_const, is_volatile, 0); - } - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - - if ((err = type_resolve(ira->codegen, ptr_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_loc; - if (type_has_bits(ira->codegen, ptr_type) && !handle_is_ptr(ira->codegen, elem_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), elem_type, nullptr, true, true); - } else { - result_loc = nullptr; - } - - Stage1AirInst *new_instruction = ir_build_ref_gen(ira, scope, source_node, ptr_type, value, result_loc); - new_instruction->value->data.rh_ptr = RuntimeHintPtrStack; - return new_instruction; -} - -static Stage1AirInst *ir_get_ref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - bool is_const, bool is_volatile) -{ - return ir_get_ref2(ira, scope, source_node, value, value->value->type, is_const, is_volatile); -} - -static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, AstNode *source_node, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - - AstNode *decl_node = union_type->data.unionation.decl_node; - if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { - assert(union_type->data.unionation.tag_type != nullptr); - return union_type->data.unionation.tag_type; - } else { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("union '%s' has no tag", - buf_ptr(&union_type->name))); - add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here")); - return ira->codegen->builtin_types.entry_invalid; - } -} - -static bool can_fold_enum_type(ZigType *ty) { - assert(ty->id == ZigTypeIdEnum); - // We can fold the enum type (and avoid any check, be it at runtime or at - // compile time) iff it has only a single element and its tag type is - // zero-sized. - ZigType *tag_int_type = ty->data.enumeration.tag_int_type; - return ty->data.enumeration.layout == ContainerLayoutAuto && - ty->data.enumeration.src_field_count == 1 && - !ty->data.enumeration.non_exhaustive && - (tag_int_type->id == ZigTypeIdInt && tag_int_type->data.integral.bit_count == 0); -} - -static Stage1AirInst *ir_analyze_enum_to_int(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target) { - Error err; - - Stage1AirInst *enum_target; - ZigType *enum_type; - if (target->value->type->id == ZigTypeIdUnion) { - enum_type = ir_resolve_union_tag_type(ira, target->source_node, target->value->type); - if (type_is_invalid(enum_type)) - return ira->codegen->invalid_inst_gen; - enum_target = ir_implicit_cast(ira, target, enum_type); - if (type_is_invalid(enum_target->value->type)) - return ira->codegen->invalid_inst_gen; - } else if (target->value->type->id == ZigTypeIdEnum) { - enum_target = target; - enum_type = target->value->type; - } else { - ir_add_error_node(ira, target->source_node, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - ZigType *tag_type = enum_type->data.enumeration.tag_int_type; - assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt); - - // If there is only one possible tag, then we know at comptime what it is. - if (can_fold_enum_type(enum_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, tag_type); - init_const_bigint(result->value, tag_type, - &enum_type->data.enumeration.fields[0].value); - return result; - } - - if (instr_is_comptime(enum_target)) { - ZigValue *val = ir_resolve_const(ira, enum_target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *result = ir_const(ira, scope, source_node, tag_type); - init_const_bigint(result->value, tag_type, &val->data.x_enum_tag); - return result; - } - - return ir_build_widen_or_shorten(ira, scope, source_node, enum_target, tag_type); -} - -static Stage1AirInst *ir_analyze_union_to_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - assert(target->value->type->id == ZigTypeIdUnion); - assert(wanted_type->id == ZigTypeIdEnum); - assert(wanted_type == target->value->type->data.unionation.tag_type); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - bigint_init_bigint(&result->value->data.x_enum_tag, &val->data.x_union.tag); - return result; - } - - // If there is only 1 possible tag, then we know at comptime what it is. - if (can_fold_enum_type(wanted_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - TypeEnumField *enum_field = target->value->type->data.unionation.fields[0].enum_field; - bigint_init_bigint(&result->value->data.x_enum_tag, &enum_field->value); - return result; - } - - return ir_build_union_tag(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_undefined_to_anything(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialUndef; - return result; -} - -static Stage1AirInst *ir_analyze_enum_to_union(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *uncasted_target, ZigType *wanted_type) -{ - Error err; - assert(wanted_type->id == ZigTypeIdUnion); - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *target = ir_implicit_cast(ira, uncasted_target, wanted_type->data.unionation.tag_type); - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); - if (union_field == nullptr) { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &target->value->data.x_enum_tag, 10); - - ir_add_error(ira, target, - buf_sprintf("no tag by value %s", buf_ptr(int_buf))); - return ira->codegen->invalid_inst_gen; - } - ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - switch (type_has_one_possible_value(ira->codegen, field_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: { - AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( - union_field->enum_field->decl_index); - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&field_type->name), - buf_ptr(union_field->name))); - add_error_note(ira->codegen, msg, field_node, - buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); - return ira->codegen->invalid_inst_gen; - } - case OnePossibleValueYes: - break; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - bigint_init_bigint(&result->value->data.x_union.tag, &val->data.x_enum_tag); - result->value->data.x_union.payload = ira->codegen->pass1_arena->create(); - result->value->data.x_union.payload->special = ConstValSpecialStatic; - result->value->data.x_union.payload->type = field_type; - return result; - } - - if (target->value->type->data.enumeration.non_exhaustive) { - ir_add_error_node(ira, source_node, - buf_sprintf("runtime cast to union '%s' from non-exhaustive enum", - buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - // if the union has all fields 0 bits, we can do it - // and in fact it's a noop cast because the union value is just the enum value - if (wanted_type->data.unionation.gen_field_count == 0) { - return ir_build_cast(ira, target->scope, target->source_node, wanted_type, target, CastOpNoop); - } - - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("runtime cast to union '%s' which has non-void fields", - buf_ptr(&wanted_type->name))); - for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { - TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; - ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - bool has_bits; - if ((err = type_has_bits2(ira->codegen, field_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - if (has_bits) { - AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); - add_error_note(ira->codegen, msg, field_node, - buf_sprintf("field '%s' has type '%s'", - buf_ptr(union_field->name), - buf_ptr(&field_type->name))); - } - } - return ira->codegen->invalid_inst_gen; -} - -static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry); - -static Stage1AirInst *ir_analyze_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - ZigType *wanted_scalar_type = (target->value->type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - - assert(wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (wanted_scalar_type->id == ZigTypeIdInt) { - if (!wanted_scalar_type->data.integral.is_signed && value_cmp_numeric_val_any(val, CmpLT, nullptr)) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to cast negative value to unsigned integer")); - return ira->codegen->invalid_inst_gen; - } - if (!value_numeric_fits_in_type(val, wanted_scalar_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("cast from '%s' to '%s' truncates bits", - buf_ptr(&target->value->type->name), buf_ptr(&wanted_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->type = wanted_type; - - if (wanted_type->id == ZigTypeIdVector) { - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(wanted_type->data.vector.len); - - for (size_t i = 0; i < wanted_type->data.vector.len; i++) { - ZigValue *scalar_dest_value = &result->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_src_value = &val->data.x_array.data.s_none.elements[i]; - - scalar_dest_value->type = wanted_scalar_type; - scalar_dest_value->special = ConstValSpecialStatic; - - if (wanted_scalar_type->id == ZigTypeIdInt) { - bigint_init_bigint(&scalar_dest_value->data.x_bigint, &scalar_src_value->data.x_bigint); - } else { - float_init_float(scalar_dest_value, scalar_src_value); - } - } - } else { - if (wanted_type->id == ZigTypeIdInt) { - bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); - } else { - float_init_float(result->value, val); - } - } - - return result; - } - - // If the destination integer type has no bits, then we can emit a comptime - // zero. However, we still want to emit a runtime safety check to make sure - // the target is zero. - if (!type_has_bits(ira->codegen, wanted_type)) { - assert(wanted_type->id == ZigTypeIdInt); - assert(type_has_bits(ira->codegen, target->value->type)); - ir_build_assert_zero(ira, scope, source_node, target); - Stage1AirInst *result = ir_const_unsigned(ira, scope, source_node, 0); - result->value->type = wanted_type; - return result; - } - - return ir_build_widen_or_shorten(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_int_to_enum(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - Error err; - assert(wanted_type->id == ZigTypeIdEnum); - - ZigType *actual_type = target->value->type; - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - if (actual_type != wanted_type->data.enumeration.tag_int_type) { - ir_add_error_node(ira, source_node, - buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'", - buf_ptr(&actual_type->name), - buf_ptr(&wanted_type->data.enumeration.tag_int_type->name))); - return ira->codegen->invalid_inst_gen; - } - - assert(actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint); - if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("enum '%s' has no tag matching integer value %s", - buf_ptr(&wanted_type->name), buf_ptr(val_buf))); - add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node, - buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &val->data.x_bigint); - return result; - } - - return ir_build_int_to_enum_gen(ira, scope, source_node, wanted_type, target); -} - -static Stage1AirInst *ir_analyze_number_to_literal(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (wanted_type->id == ZigTypeIdComptimeFloat) { - float_init_float(result->value, val); - } else if (wanted_type->id == ZigTypeIdComptimeInt) { - bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); - } else { - zig_unreachable(); - } - return result; -} - -static Stage1AirInst *ir_analyze_int_to_err(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(target->value->type->id == ZigTypeIdInt); - assert(!target->value->type->data.integral.is_signed); - assert(wanted_type->id == ZigTypeIdErrorSet); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - - if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (type_is_global_error_set(wanted_type)) { - BigInt err_count; - bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length); - - if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ir_add_error_node(ira, source_node, - buf_sprintf("integer value %s represents no error", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - - size_t index = bigint_as_usize(&val->data.x_bigint); - result->value->data.x_err_set = ira->codegen->errors_by_index.at(index); - return result; - } else { - ErrorTableEntry *err = nullptr; - BigInt err_int; - - for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { - ErrorTableEntry *this_err = wanted_type->data.error_set.errors[i]; - bigint_init_unsigned(&err_int, this_err->value); - if (bigint_cmp(&val->data.x_bigint, &err_int) == CmpEQ) { - err = this_err; - break; - } - } - - if (err == nullptr) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ir_add_error_node(ira, source_node, - buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - result->value->data.x_err_set = err; - return result; - } - } - - return ir_build_int_to_err_gen(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_err_to_int(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdInt); - - ZigType *err_type = target->value->type; - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - - ErrorTableEntry *err; - if (err_type->id == ZigTypeIdErrorUnion) { - err = val->data.x_err_union.error_set->data.x_err_set; - } else if (err_type->id == ZigTypeIdErrorSet) { - err = val->data.x_err_set; - } else { - zig_unreachable(); - } - result->value->type = wanted_type; - uint64_t err_value = err ? err->value : 0; - bigint_init_unsigned(&result->value->data.x_bigint, err_value); - - if (!bigint_fits_in_bits(&result->value->data.x_bigint, - wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) - { - ir_add_error_node(ira, source_node, - buf_sprintf("error code '%s' does not fit in '%s'", - buf_ptr(&err->name), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return result; - } - - ZigType *err_set_type; - if (err_type->id == ZigTypeIdErrorUnion) { - err_set_type = err_type->data.error_union.err_set_type; - } else if (err_type->id == ZigTypeIdErrorSet) { - err_set_type = err_type; - } else { - zig_unreachable(); - } - if (!type_is_global_error_set(err_set_type)) { - if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (err_set_type->data.error_set.err_count == 0) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - return result; - } else if (err_set_type->data.error_set.err_count == 1) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; - bigint_init_unsigned(&result->value->data.x_bigint, err->value); - return result; - } - } - - BigInt bn; - bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); - if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { - ir_add_error_node(ira, source_node, - buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_err_to_int_gen(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_ptr_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdPointer); - Error err; - if ((err = type_resolve(ira->codegen, target->value->type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - assert((wanted_type->data.pointer.is_const && target->value->type->data.pointer.is_const) || !target->value->type->data.pointer.is_const); - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, target->value->type)); - ZigType *array_type = wanted_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - assert(array_type->data.array.len == 1); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - assert(val->type->id == ZigTypeIdPointer); - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - ZigValue *array_val = ira->codegen->pass1_arena->create(); - array_val->special = ConstValSpecialStatic; - array_val->type = array_type; - array_val->data.x_array.special = ConstArraySpecialNone; - array_val->data.x_array.data.s_none.elements = pointee; - array_val->parent.id = ConstParentIdScalar; - array_val->parent.data.p_scalar.scalar_val = pointee; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_ptr.special = ConstPtrSpecialRef; - const_instruction->base.value->data.x_ptr.data.ref.pointee = array_val; - const_instruction->base.value->data.x_ptr.mut = val->data.x_ptr.mut; - return &const_instruction->base; - } - } - - // pointer to array and pointer to single item are represented the same way at runtime - return ir_build_cast(ira, target->scope, target->source_node, wanted_type, target, CastOpBitCast); -} - -static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCastOnly *cast_result, - ErrorMsg *parent_msg) -{ - switch (cast_result->id) { - case ConstCastResultIdOk: - zig_unreachable(); - case ConstCastResultIdInvalid: - zig_unreachable(); - case ConstCastResultIdOptionalChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'", - buf_ptr(&cast_result->data.optional->actual_child->name), - buf_ptr(&cast_result->data.optional->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg); - break; - } - case ConstCastResultIdOptionalShape: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("optional type child '%s' cannot cast into optional type '%s'", - buf_ptr(&cast_result->data.type_mismatch->actual_type->name), - buf_ptr(&cast_result->data.type_mismatch->wanted_type->name))); - break; - } - case ConstCastResultIdErrorUnionErrorSet: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("error set '%s' cannot cast into error set '%s'", - buf_ptr(&cast_result->data.error_union_error_set->actual_err_set->name), - buf_ptr(&cast_result->data.error_union_error_set->wanted_err_set->name))); - report_recursive_error(ira, source_node, &cast_result->data.error_union_error_set->child, msg); - break; - } - case ConstCastResultIdErrSet: { - ZigList *missing_errors = &cast_result->data.error_set_mismatch->missing_errors; - for (size_t i = 0; i < missing_errors->length; i += 1) { - ErrorTableEntry *error_entry = missing_errors->at(i); - add_error_note(ira->codegen, parent_msg, ast_field_to_symbol_node(error_entry->decl_node), - buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name))); - } - break; - } - case ConstCastResultIdErrSetGlobal: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("cannot cast global error set into smaller set")); - break; - } - case ConstCastResultIdPointerChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("pointer type child '%s' cannot cast into pointer type child '%s'", - buf_ptr(&cast_result->data.pointer_mismatch->actual_child->name), - buf_ptr(&cast_result->data.pointer_mismatch->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.pointer_mismatch->child, msg); - break; - } - case ConstCastResultIdSliceChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("slice type child '%s' cannot cast into slice type child '%s'", - buf_ptr(&cast_result->data.slice_mismatch->actual_child->name), - buf_ptr(&cast_result->data.slice_mismatch->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.slice_mismatch->child, msg); - break; - } - case ConstCastResultIdErrorUnionPayload: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("error union payload '%s' cannot cast into error union payload '%s'", - buf_ptr(&cast_result->data.error_union_payload->actual_payload->name), - buf_ptr(&cast_result->data.error_union_payload->wanted_payload->name))); - report_recursive_error(ira, source_node, &cast_result->data.error_union_payload->child, msg); - break; - } - case ConstCastResultIdType: { - AstNode *wanted_decl_node = type_decl_node(cast_result->data.type_mismatch->wanted_type); - AstNode *actual_decl_node = type_decl_node(cast_result->data.type_mismatch->actual_type); - if (wanted_decl_node != nullptr) { - add_error_note(ira->codegen, parent_msg, wanted_decl_node, - buf_sprintf("%s declared here", - buf_ptr(&cast_result->data.type_mismatch->wanted_type->name))); - } - if (actual_decl_node != nullptr) { - add_error_note(ira->codegen, parent_msg, actual_decl_node, - buf_sprintf("%s declared here", - buf_ptr(&cast_result->data.type_mismatch->actual_type->name))); - } - break; - } - case ConstCastResultIdFnArg: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("parameter %" ZIG_PRI_usize ": '%s' cannot cast into '%s'", - cast_result->data.fn_arg.arg_index, - buf_ptr(&cast_result->data.fn_arg.actual_param_type->name), - buf_ptr(&cast_result->data.fn_arg.expected_param_type->name))); - report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); - break; - } - case ConstCastResultIdBadAllowsZero: { - ZigType *wanted_type = cast_result->data.bad_allows_zero->wanted_type; - ZigType *actual_type = cast_result->data.bad_allows_zero->actual_type; - bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(actual_type); - if (actual_allows_zero && !wanted_allows_zero) { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("'%s' could have null values which are illegal in type '%s'", - buf_ptr(&actual_type->name), - buf_ptr(&wanted_type->name))); - } else { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - } - break; - } - case ConstCastResultIdPtrLens: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("pointer length mismatch")); - break; - } - case ConstCastResultIdPtrSentinel: { - ZigType *actual_type = cast_result->data.bad_ptr_sentinel->actual_type; - ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type; - { - Buf *txt_msg = buf_sprintf("destination pointer requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel); - buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.pointer.sentinel != nullptr) { - buf_appendf(txt_msg, ", but source pointer has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.pointer.sentinel); - buf_appendf(txt_msg, "' sentinel"); - } - add_error_note(ira->codegen, parent_msg, source_node, txt_msg); - } - break; - } - case ConstCastResultIdSentinelArrays: { - ZigType *actual_type = cast_result->data.sentinel_arrays->actual_type; - ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type; - Buf *txt_msg = buf_sprintf("destination array requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.array.sentinel); - buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.array.sentinel != nullptr) { - buf_appendf(txt_msg, ", but source array has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.array.sentinel); - buf_appendf(txt_msg, "' sentinel"); - } - add_error_note(ira->codegen, parent_msg, source_node, txt_msg); - break; - } - case ConstCastResultIdCV: { - ZigType *wanted_type = cast_result->data.bad_cv->wanted_type; - ZigType *actual_type = cast_result->data.bad_cv->actual_type; - bool ok_const = !actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const; - bool ok_volatile = !actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile; - if (!ok_const) { - add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards const qualifier")); - } else if (!ok_volatile) { - add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards volatile qualifier")); - } else { - zig_unreachable(); - } - break; - } - case ConstCastResultIdFnIsGeneric: - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("only one of the functions is generic")); - break; - case ConstCastResultIdFnCC: - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("calling convention mismatch")); - break; - case ConstCastResultIdIntShorten: { - ZigType *wanted_type = cast_result->data.int_shorten->wanted_type; - ZigType *actual_type = cast_result->data.int_shorten->actual_type; - const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; - const char *actual_signed = actual_type->data.integral.is_signed ? "signed" : "unsigned"; - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values", - wanted_signed, wanted_type->data.integral.bit_count, - actual_signed, actual_type->data.integral.bit_count)); - break; - } - case ConstCastResultIdVectorLength: // TODO - case ConstCastResultIdVectorChild: // TODO - case ConstCastResultIdFnAlign: // TODO - case ConstCastResultIdFnVarArgs: // TODO - case ConstCastResultIdFnReturnType: // TODO - case ConstCastResultIdFnArgCount: // TODO - case ConstCastResultIdFnGenericArgCount: // TODO - case ConstCastResultIdFnArgNoAlias: // TODO - case ConstCastResultIdUnresolvedInferredErrSet: // TODO - case ConstCastResultIdAsyncAllocatorType: // TODO - case ConstCastResultIdArrayChild: // TODO - break; - } -} - -static Stage1AirInst *ir_analyze_array_to_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array, ZigType *vector_type) -{ - if (instr_is_comptime(array)) { - // arrays and vectors have the same ZigValue representation - Stage1AirInst *result = ir_const(ira, scope, source_node, vector_type); - copy_const_val(ira->codegen, result->value, array->value); - result->value->type = vector_type; - return result; - } - return ir_build_array_to_vector(ira, scope, source_node, array, vector_type); -} - -static Stage1AirInst *ir_analyze_vector_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector, ZigType *array_type, ResultLoc *result_loc) -{ - if (instr_is_comptime(vector)) { - // arrays and vectors have the same ZigValue representation - Stage1AirInst *result = ir_const(ira, scope, source_node, array_type); - copy_const_val(ira->codegen, result->value, vector->value); - result->value->type = array_type; - return result; - } - if (result_loc == nullptr) { - result_loc = no_result_loc(); - } - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, array_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - return ir_build_vector_to_array(ira, scope, source_node, array_type, vector, result_loc_inst); -} - -static Stage1AirInst *ir_analyze_int_to_c_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *integer, ZigType *dest_type) -{ - Stage1AirInst *unsigned_integer; - if (instr_is_comptime(integer)) { - unsigned_integer = integer; - } else { - assert(integer->value->type->id == ZigTypeIdInt); - - if (integer->value->type->data.integral.bit_count > - ira->codegen->builtin_types.entry_usize->data.integral.bit_count) - { - ir_add_error_node(ira, source_node, - buf_sprintf("integer type '%s' too big for implicit @intToPtr to type '%s'", - buf_ptr(&integer->value->type->name), - buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (integer->value->type->data.integral.is_signed) { - ZigType *unsigned_int_type = get_int_type(ira->codegen, false, - integer->value->type->data.integral.bit_count); - unsigned_integer = ir_analyze_bit_cast(ira, scope, source_node, integer, unsigned_int_type); - if (type_is_invalid(unsigned_integer->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - unsigned_integer = integer; - } - } - - return ir_analyze_int_to_ptr(ira, scope, source_node, unsigned_integer, dest_type); -} - -static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) { - if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer; - if (ty->id == ZigTypeIdFn) return true; - if (ty->id == ZigTypeIdOptional) { - ZigType *ptr_ty = ty->data.maybe.child_type; - if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer; - if (ptr_ty->id == ZigTypeIdFn) return true; - } - return false; -} - -static Stage1AirInst *ir_analyze_enum_literal(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *enum_type) -{ - assert(enum_type->id == ZigTypeIdEnum); - - Error err; - if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_type_field(enum_type, value->value->data.x_enum_literal); - if (field == nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("enum '%s' has no field named '%s'", - buf_ptr(&enum_type->name), buf_ptr(value->value->data.x_enum_literal))); - add_error_note(ira->codegen, msg, enum_type->data.enumeration.decl_node, - buf_sprintf("'%s' declared here", buf_ptr(&enum_type->name))); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_const(ira, scope, source_node, enum_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &field->value); - - return result; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *actual_type, ZigType *wanted_type) -{ - Error err; - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t array_len = wanted_type->data.array.len; - size_t instr_field_count = actual_type->data.structure.src_field_count; - assert(array_len == instr_field_count); - - bool need_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes; - bool is_comptime = true; - - ZigType *elem_type = wanted_type->data.array.child_type; - - // Determine if the struct_operand will be comptime. - ZigValue *elem_values = heap::c_allocator.allocate(array_len); - Stage1AirInst **casted_fields = heap::c_allocator.allocate(array_len); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - - for (size_t i = 0; i < array_len; i += 1) { - TypeStructField *src_field = actual_type->data.structure.fields[i]; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, src_field, struct_ptr, - actual_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, elem_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_fields[i] = casted_value; - if (need_comptime || instr_is_comptime(casted_value)) { - ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk); - if (field_val == nullptr) - return ira->codegen->invalid_inst_gen; - - field_val->parent.id = ConstParentIdArray; - field_val->parent.data.p_array.array_val = const_result->value; - field_val->parent.data.p_array.elem_index = i; - elem_values[i] = *field_val; - if (field_val->type->id == ZigTypeIdUndefined) { - elem_values[i].special = ConstValSpecialUndef; - } - } else { - is_comptime = false; - } - } - - if (is_comptime) { - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - const_result->value->data.x_array.special = ConstArraySpecialNone; - const_result->value->data.x_array.data.s_none.elements = elem_values; - return const_result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - ZigType *elem_type_ptr = get_pointer_to_type(ira->codegen, elem_type, false); - for (size_t i = 0; i < array_len; i += 1) { - Stage1AirInst *index_val = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_usize); - bigint_init_unsigned(&index_val->value->data.x_bigint, i); - - Stage1AirInst *elem_ptr = ir_build_elem_ptr_gen(ira, scope, source_node, - result_loc_inst, index_val, false, elem_type_ptr); - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, elem_ptr, casted_fields[i], true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - heap::c_allocator.deallocate(elem_values, array_len); - heap::c_allocator.deallocate(casted_fields, array_len); - - return result_loc_inst; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *actual_type, ZigType *wanted_type) -{ - Error err; - - if (wanted_type->data.structure.resolve_status == ResolveStatusBeingInferred) { - ir_add_error_node(ira, source_node, buf_sprintf("type coercion of anon struct literal to inferred struct")); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t actual_field_count = wanted_type->data.structure.src_field_count; - size_t instr_field_count = actual_type->data.structure.src_field_count; - - bool need_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes; - bool is_comptime = true; - - // Determine if the struct_operand will be comptime. - // Also emit compile errors for missing fields and duplicate fields. - AstNode **field_assign_nodes = heap::c_allocator.allocate(actual_field_count); - ZigValue **field_values = heap::c_allocator.allocate(actual_field_count); - Stage1AirInst **casted_fields = heap::c_allocator.allocate(actual_field_count); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - - for (size_t i = 0; i < instr_field_count; i += 1) { - TypeStructField *src_field = actual_type->data.structure.fields[i]; - TypeStructField *dst_field = find_struct_type_field(wanted_type, src_field->name); - if (dst_field == nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("no field named '%s' in struct '%s'", - buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); - if (wanted_type->data.structure.decl_node) { - add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, - buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); - } - add_error_note(ira->codegen, msg, src_field->decl_node, - buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); - return ira->codegen->invalid_inst_gen; - } - if (dst_field->is_comptime) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("field '%s' in struct '%s' is comptime, it cannot be assigned", - buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); - if (wanted_type->data.structure.decl_node) { - add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, - buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); - } - add_error_note(ira->codegen, msg, src_field->decl_node, - buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); - return ira->codegen->invalid_inst_gen; - } - - src_assert(src_field->decl_node != nullptr, source_node); - AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index]; - if (existing_assign_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("duplicate field")); - add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); - return ira->codegen->invalid_inst_gen; - } - field_assign_nodes[dst_field->src_index] = src_field->decl_node; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, src_field, struct_ptr, - actual_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, dst_field->type_entry); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_fields[dst_field->src_index] = casted_value; - if (need_comptime || instr_is_comptime(casted_value)) { - ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk); - if (field_val == nullptr) - return ira->codegen->invalid_inst_gen; - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = const_result->value; - field_val->parent.data.p_struct.field_index = dst_field->src_index; - field_values[dst_field->src_index] = field_val; - if (field_val->type->id == ZigTypeIdUndefined && dst_field->type_entry->id != ZigTypeIdUndefined) { - field_values[dst_field->src_index]->special = ConstValSpecialUndef; - } - } else { - is_comptime = false; - } - } - - bool any_missing = false; - for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i] != nullptr) continue; - - // look for a default field value - TypeStructField *field = wanted_type->data.structure.fields[i]; - assert(!field->is_comptime); // field_assign_nodes[i] should be null for comptime fields - memoize_field_init_val(ira->codegen, wanted_type, field); - if (field->init_val == nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("missing field: '%s'", buf_ptr(field->name))); - any_missing = true; - continue; - } - if (type_is_invalid(field->init_val->type)) - return ira->codegen->invalid_inst_gen; - ZigValue *init_val_copy = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, init_val_copy, field->init_val); - init_val_copy->parent.id = ConstParentIdStruct; - init_val_copy->parent.data.p_struct.struct_val = const_result->value; - init_val_copy->parent.data.p_struct.field_index = i; - field_values[i] = init_val_copy; - casted_fields[i] = ir_const_move(ira, scope, source_node, init_val_copy); - } - if (any_missing) - return ira->codegen->invalid_inst_gen; - - if (is_comptime) { - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - const_result->value->data.x_struct.fields = field_values; - return const_result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - for (size_t i = 0; i < actual_field_count; i += 1) { - TypeStructField *field = wanted_type->data.structure.fields[i]; - if (field->is_comptime) - continue; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, result_loc_inst, wanted_type, true); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, field_ptr, casted_fields[i], true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - heap::c_allocator.deallocate(field_values, actual_field_count); - heap::c_allocator.deallocate(casted_fields, actual_field_count); - - return result_loc_inst; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_union(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *struct_type, ZigType *union_type) -{ - Error err; - - assert(struct_type->id == ZigTypeIdStruct); - assert(union_type->id == ZigTypeIdUnion); - assert(struct_type->data.structure.src_field_count == 1); - - TypeStructField *only_field = struct_type->data.structure.fields[0]; - - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *union_field = find_union_type_field(union_type, only_field->name); - if (union_field == nullptr) { - ir_add_error_node(ira, only_field->decl_node, - buf_sprintf("no field named '%s' in union '%s'", - buf_ptr(only_field->name), buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *payload_type = resolve_union_field_type(ira->codegen, union_field); - if (payload_type == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, only_field, struct_ptr, - struct_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, payload_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, union_type); - bigint_init_bigint(&result->value->data.x_union.tag, &union_field->enum_field->value); - result->value->data.x_union.payload = val; - - val->parent.id = ConstParentIdUnion; - val->parent.data.p_union.union_val = result->value; - - return result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - union_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *payload_ptr = ir_analyze_container_field_ptr(ira, only_field->name, - scope, source_node, result_loc_inst, source_node, union_type, true); - if (type_is_invalid(payload_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, payload_ptr, casted_value, false); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - return result_loc_inst; -} - -// Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work, -// otherwise return ErrorNone. Does not emit any instructions. -// Assumes that the pointer types have element types with the same ABI alignment. Avoids resolving the -// pointer types' alignments if both of the pointer types are ABI aligned. -static Error ir_cast_ptr_align(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *dest_ptr_type, - ZigType *src_ptr_type, AstNode *src_source_node) -{ - Error err; - - src_assert(dest_ptr_type->id == ZigTypeIdPointer, source_node); - src_assert(src_ptr_type->id == ZigTypeIdPointer, source_node); - - if (dest_ptr_type->data.pointer.explicit_alignment == 0 && - src_ptr_type->data.pointer.explicit_alignment == 0) - { - return ErrorNone; - } - - if ((err = type_resolve(ira->codegen, dest_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ErrorSemanticAnalyzeFail; - - if ((err = type_resolve(ira->codegen, src_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ErrorSemanticAnalyzeFail; - - uint32_t wanted_align = get_ptr_align(ira->codegen, dest_ptr_type); - uint32_t actual_align = get_ptr_align(ira->codegen, src_ptr_type); - if (wanted_align > actual_align) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cast increases pointer alignment")); - add_error_note(ira->codegen, msg, src_source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_ptr_type->name), actual_align)); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_ptr_type->name), wanted_align)); - return ErrorSemanticAnalyzeFail; - } - - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_struct_value_field_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_operand, TypeStructField *field) -{ - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, struct_operand, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, struct_ptr, - struct_operand->value->type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_get_deref(ira, scope, source_node, field_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_optional_value_payload_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *optional_operand, bool safety_check_on) -{ - Stage1AirInst *opt_ptr = ir_get_ref(ira, scope, source_node, optional_operand, true, false); - Stage1AirInst *payload_ptr = ir_analyze_unwrap_optional_payload(ira, scope, source_node, opt_ptr, - safety_check_on, false); - return ir_get_deref(ira, scope, source_node, payload_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *wanted_type, Stage1AirInst *value) -{ - Error err; - ZigType *actual_type = value->value->type; - - if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) { - return ira->codegen->invalid_inst_gen; - } - - // This means the wanted type is anything. - if (wanted_type == ira->codegen->builtin_types.entry_anytype) { - return value; - } - - // perfect match or non-const to const - ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type, - source_node, false); - if (const_cast_result.id == ConstCastResultIdInvalid) - return ira->codegen->invalid_inst_gen; - if (const_cast_result.id == ConstCastResultIdOk) { - return ir_resolve_cast(ira, scope, source_node, value, wanted_type, CastOpNoop); - } - - if (const_cast_result.id == ConstCastResultIdFnCC) { - src_assert(value->value->type->id == ZigTypeIdFn, source_node); - // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. - if (wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync && - actual_type->data.fn.fn_type_id.cc == CallingConventionUnspecified) - { - src_assert(value->value->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - ZigFn *fn = value->value->data.x_ptr.data.fn.fn_entry; - if (fn->inferred_async_node == nullptr) { - fn->inferred_async_node = source_node; - } - return ir_resolve_cast(ira, scope, source_node, value, wanted_type, CastOpNoop); - } - } - - // cast from T to ?T - // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism - if (wanted_type->id == ZigTypeIdOptional) { - ZigType *wanted_child_type = wanted_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, - false).id == ConstCastResultIdOk) - { - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } else { - return ira->codegen->invalid_inst_gen; - } - } else if ( - wanted_child_type->id == ZigTypeIdPointer && - wanted_child_type->data.pointer.ptr_len == PtrLenUnknown && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) && - types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - Stage1AirInst *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, scope, source_node, value, - wanted_child_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_optional_wrap(ira, scope, source_node, cast1, wanted_type, nullptr); - } - } - } - - // T to E!T - if (wanted_type->id == ZigTypeIdErrorUnion) { - if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, - source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } else { - return ira->codegen->invalid_inst_gen; - } - } - } - - // cast from T to E!?T - if (wanted_type->id == ZigTypeIdErrorUnion && - wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional && - actual_type->id != ZigTypeIdOptional) - { - ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk || - actual_type->id == ZigTypeIdNull || - actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, wanted_type->data.error_union.payload_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } - } - - - // cast from comptime-known number to another number type - if (instr_is_comptime(value) && - (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdFloat || actual_type->id == ZigTypeIdComptimeFloat) && - (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || - wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) - { - if (value->value->special == ConstValSpecialUndef) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialUndef; - return result; - } - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { - if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { - copy_const_val(ira->codegen, result->value, value->value); - result->value->type = wanted_type; - } else { - float_init_bigint(&result->value->data.x_bigint, value->value); - } - return result; - } else if (wanted_type->id == ZigTypeIdComptimeFloat || wanted_type->id == ZigTypeIdFloat) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { - BigFloat bf; - bigfloat_init_bigint(&bf, &value->value->data.x_bigint); - float_init_bigfloat(result->value, &bf); - } else { - float_init_float(result->value, value->value); - } - return result; - } - zig_unreachable(); - } else { - return ira->codegen->invalid_inst_gen; - } - } - - // widening conversion - if (wanted_type->id == ZigTypeIdInt && - actual_type->id == ZigTypeIdInt && - wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed && - wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // small enough unsigned ints can get casted to large enough signed ints - if (wanted_type->id == ZigTypeIdInt && wanted_type->data.integral.is_signed && - actual_type->id == ZigTypeIdInt && !actual_type->data.integral.is_signed && - wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // float widening conversion - if (wanted_type->id == ZigTypeIdFloat && - actual_type->id == ZigTypeIdFloat && - wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // *[N]T to ?[]T - if (wanted_type->id == ZigTypeIdOptional && - is_slice(wanted_type->data.maybe.child_type) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, wanted_type->data.maybe.child_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } - - // *[N]T to [*]T and [*c]T - if (wanted_type->id == ZigTypeIdPointer && - (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - ZigType *actual_array_type = actual_type->data.pointer.child_type; - if (wanted_type->data.pointer.sentinel == nullptr || - (actual_array_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, - actual_array_type->data.array.sentinel))) - { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, scope, source_node, value, wanted_type); - } - } - } - - // *[N]T to []T - // *[N]T to E![]T - if ((is_slice(wanted_type) || - (wanted_type->id == ZigTypeIdErrorUnion && - is_slice(wanted_type->data.error_union.payload_type))) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *slice_type = (wanted_type->id == ZigTypeIdErrorUnion) ? - wanted_type->data.error_union.payload_type : wanted_type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - assert(slice_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 - || !actual_type->data.pointer.is_const); - - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, - !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk && - (slice_ptr_type->data.pointer.sentinel == nullptr || - (array_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, array_type->data.array.sentinel, - slice_ptr_type->data.pointer.sentinel)))) - { - if (!const_ok) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to slice type '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - // If the pointers both have ABI align, it works. - // Or if the array length is 0, alignment doesn't matter. - bool ok_align = array_type->data.array.len == 0 || - (slice_ptr_type->data.pointer.explicit_alignment == 0 && - actual_type->data.pointer.explicit_alignment == 0); - if (!ok_align) { - // If either one has non ABI align, we have to resolve them both - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); - } - if (ok_align) { - if (wanted_type->id == ZigTypeIdErrorUnion) { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, slice_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } else { - return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, value, slice_type, nullptr); - } - } - } - } - - // @Vector(N,T1) to @Vector(N,T2) - if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector && - actual_type->data.vector.len == wanted_type->data.vector.len) - { - ZigType *scalar_actual_type = actual_type->data.vector.elem_type; - ZigType *scalar_wanted_type = wanted_type->data.vector.elem_type; - - // widening conversion - if (scalar_wanted_type->id == ZigTypeIdInt && - scalar_actual_type->id == ZigTypeIdInt && - scalar_wanted_type->data.integral.is_signed == scalar_actual_type->data.integral.is_signed && - scalar_wanted_type->data.integral.bit_count >= scalar_actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // small enough unsigned ints can get casted to large enough signed ints - if (scalar_wanted_type->id == ZigTypeIdInt && scalar_wanted_type->data.integral.is_signed && - scalar_actual_type->id == ZigTypeIdInt && !scalar_actual_type->data.integral.is_signed && - scalar_wanted_type->data.integral.bit_count > scalar_actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // float widening conversion - if (scalar_wanted_type->id == ZigTypeIdFloat && - scalar_actual_type->id == ZigTypeIdFloat && - scalar_wanted_type->data.floating.bit_count >= scalar_actual_type->data.floating.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - } - - // *@Frame(func) to anyframe->T or anyframe - // *@Frame(func) to ?anyframe->T or ?anyframe - // *@Frame(func) to E!anyframe->T or E!anyframe - if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && - !actual_type->data.pointer.is_const && - actual_type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *anyframe_type; - if (wanted_type->id == ZigTypeIdAnyFrame) { - anyframe_type = wanted_type; - } else if (wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdAnyFrame) - { - anyframe_type = wanted_type->data.maybe.child_type; - } else if (wanted_type->id == ZigTypeIdErrorUnion && - wanted_type->data.error_union.payload_type->id == ZigTypeIdAnyFrame) - { - anyframe_type = wanted_type->data.error_union.payload_type; - } else { - anyframe_type = nullptr; - } - if (anyframe_type != nullptr) { - bool ok = true; - if (anyframe_type->data.any_frame.result_type != nullptr) { - ZigFn *fn = actual_type->data.pointer.child_type->data.frame.fn; - ZigType *fn_return_type = fn->type_entry->data.fn.fn_type_id.return_type; - if (anyframe_type->data.any_frame.result_type != fn_return_type) { - ok = false; - } - } - if (ok) { - Stage1AirInst *cast1 = ir_analyze_frame_ptr_to_anyframe(ira, scope, source_node, value, anyframe_type); - if (anyframe_type == wanted_type) - return cast1; - return ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - } - } - } - - // anyframe->T to anyframe - if (actual_type->id == ZigTypeIdAnyFrame && actual_type->data.any_frame.result_type != nullptr && - wanted_type->id == ZigTypeIdAnyFrame && wanted_type->data.any_frame.result_type == nullptr) - { - return ir_analyze_anyframe_to_anyframe(ira, scope, source_node, value, wanted_type); - } - - // cast from null literal to maybe type - if (wanted_type->id == ZigTypeIdOptional && - actual_type->id == ZigTypeIdNull) - { - return ir_analyze_null_to_maybe(ira, scope, source_node, value, wanted_type); - } - - // cast from null literal to C pointer - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && - actual_type->id == ZigTypeIdNull) - { - return ir_analyze_null_to_c_pointer(ira, scope, source_node, value, wanted_type); - } - - // cast from E to E!T - if (wanted_type->id == ZigTypeIdErrorUnion && - actual_type->id == ZigTypeIdErrorSet) - { - return ir_analyze_err_wrap_code(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from typed number to integer or float literal. - // works when the number is known at compile time - if (instr_is_comptime(value) && - ((actual_type->id == ZigTypeIdInt && wanted_type->id == ZigTypeIdComptimeInt) || - (actual_type->id == ZigTypeIdFloat && wanted_type->id == ZigTypeIdComptimeFloat))) - { - return ir_analyze_number_to_literal(ira, scope, source_node, value, wanted_type); - } - - // cast from enum literal to enum with matching field name - if (actual_type->id == ZigTypeIdEnumLiteral && wanted_type->id == ZigTypeIdEnum) - { - return ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type); - } - - // cast from enum literal to optional enum - if (actual_type->id == ZigTypeIdEnumLiteral && - (wanted_type->id == ZigTypeIdOptional && wanted_type->data.maybe.child_type->id == ZigTypeIdEnum)) - { - Stage1AirInst *result = ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type->data.maybe.child_type); - if (type_is_invalid(result->value->type)) - return result; - - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from enum literal to error union when payload is an enum - if (actual_type->id == ZigTypeIdEnumLiteral && - (wanted_type->id == ZigTypeIdErrorUnion && wanted_type->data.error_union.payload_type->id == ZigTypeIdEnum)) - { - Stage1AirInst *result = ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type->data.error_union.payload_type); - if (type_is_invalid(result->value->type)) - return result; - - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from union to the enum type of the union - if (actual_type->id == ZigTypeIdUnion && wanted_type->id == ZigTypeIdEnum) { - if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (actual_type->data.unionation.tag_type == wanted_type) { - return ir_analyze_union_to_tag(ira, scope, source_node, value, wanted_type); - } - } - - // enum to union which has the enum as the tag type, or - // enum literal to union which has a matching enum as the tag type - if (is_tagged_union(wanted_type) && (actual_type->id == ZigTypeIdEnum || - actual_type->id == ZigTypeIdEnumLiteral)) - { - return ir_analyze_enum_to_union(ira, scope, source_node, value, wanted_type); - } - - // cast from *T to *[1]T - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle) - { - ZigType *array_type = wanted_type->data.pointer.child_type; - if (array_type->id == ZigTypeIdArray && array_type->data.array.len == 1 && - types_match_const_cast_only(ira, array_type->data.array.child_type, - actual_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - // `types_match_const_cast_only` only gets info for child_types - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - if ((err = ir_cast_ptr_align(ira, scope, source_node, wanted_type, actual_type, value->source_node))) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_ptr_to_array(ira, scope, source_node, value, wanted_type); - } - } - - // [:x]T to [*:x]T - // [:x]T to [*c]T - if (wanted_type->id == ZigTypeIdPointer && is_slice(actual_type) && - ((wanted_type->data.pointer.ptr_len == PtrLenUnknown && wanted_type->data.pointer.sentinel != nullptr) || - wanted_type->data.pointer.ptr_len == PtrLenC)) - { - ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, - actual_type->data.structure.fields[slice_ptr_index]); - if (types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - slice_ptr_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - (slice_ptr_type->data.pointer.sentinel != nullptr && - (wanted_type->data.pointer.ptr_len == PtrLenC || - const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, - slice_ptr_type->data.pointer.sentinel)))) - { - TypeStructField *ptr_field = actual_type->data.structure.fields[slice_ptr_index]; - Stage1AirInst *slice_ptr = ir_analyze_struct_value_field_value(ira, scope, source_node, value, ptr_field); - return ir_implicit_cast2(ira, scope, source_node, slice_ptr, wanted_type); - } - } - - // cast from *T and [*]T to *anyopaque and ?*anyopaque - // but don't do it if the actual type is a double pointer - if (is_pointery_and_elem_is_not_pointery(actual_type)) { - ZigType *dest_ptr_type = nullptr; - if (wanted_type->id == ZigTypeIdPointer && - actual_type->id != ZigTypeIdOptional && - wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_anyopaque) - { - dest_ptr_type = wanted_type; - } else if (wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && - wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_anyopaque) - { - dest_ptr_type = wanted_type->data.maybe.child_type; - } - if (dest_ptr_type != nullptr) { - return ir_analyze_ptr_cast(ira, scope, source_node, value, source_node, - wanted_type, source_node, true, false); - } - } - - // cast from T to *T where T is zero bits - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool has_bits; - if ((err = type_has_bits2(ira->codegen, actual_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - if (!has_bits) { - return ir_get_ref(ira, scope, source_node, value, false, false); - } - } - - // cast from @Vector(N, T) to [N]T - if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector && - wanted_type->data.array.len == actual_type->data.vector.len && - types_match_const_cast_only(ira, wanted_type->data.array.child_type, - actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_vector_to_array(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from [N]T to @Vector(N, T) - if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector && - actual_type->data.array.len == wanted_type->data.vector.len && - types_match_const_cast_only(ira, actual_type->data.array.child_type, - wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_array_to_vector(ira, scope, source_node, value, wanted_type); - } - - // casting between C pointers and normal pointers - if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer && - (wanted_type->data.pointer.ptr_len == PtrLenC || actual_type->data.pointer.ptr_len == PtrLenC) && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - return ir_analyze_ptr_cast(ira, scope, source_node, value, source_node, - wanted_type, source_node, true, false); - } - - // cast from integer to C pointer - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && - (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt)) - { - return ir_analyze_int_to_c_ptr(ira, scope, source_node, value, wanted_type); - } - - // cast from inferred struct type to array, union, or struct - if (is_anon_container(actual_type)) { - const bool is_array_init = - actual_type->data.structure.special == StructSpecialInferredTuple; - const uint32_t field_count = actual_type->data.structure.src_field_count; - - if (wanted_type->id == ZigTypeIdArray && (is_array_init || field_count == 0) && - wanted_type->data.array.len == field_count) - { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_array(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } else if (wanted_type->id == ZigTypeIdStruct && !is_slice(wanted_type) && - (!is_array_init || field_count == 0)) - { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_struct(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } else if (wanted_type->id == ZigTypeIdUnion && !is_array_init && field_count == 1) { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_union(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } - } - - // cast from pointer to inferred struct type to pointer to array, union, or struct - if (actual_type->id == ZigTypeIdPointer && is_anon_container(actual_type->data.pointer.child_type)) { - ZigType *anon_type = actual_type->data.pointer.child_type; - const bool is_array_init = - anon_type->data.structure.special == StructSpecialInferredTuple; - const uint32_t field_count = anon_type->data.structure.src_field_count; - - if (wanted_type->id == ZigTypeIdPointer && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - ZigType *wanted_child = wanted_type->data.pointer.child_type; - bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const); - if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) && - wanted_child->data.array.len == field_count) - { - if (!const_ok && field_count != 0) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } else if (wanted_child->id == ZigTypeIdStruct && !is_slice(wanted_type) && - (!is_array_init || field_count == 0) && const_ok) - { - Stage1AirInst *res = ir_analyze_struct_literal_to_struct(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } else if (wanted_child->id == ZigTypeIdUnion && !is_array_init && field_count == 1 && const_ok) { - Stage1AirInst *res = ir_analyze_struct_literal_to_union(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } - } else if (is_slice(wanted_type) && (is_array_init || field_count == 0)) { - ZigType *slice_type = wanted_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((!actual_type->data.pointer.is_const || slice_type->data.pointer.is_const || field_count == 0) && - (!actual_type->data.pointer.is_volatile || slice_type->data.pointer.is_volatile)) - { - ZigType *slice_child_type = slice_type->data.pointer.child_type; - ZigType *slice_array_type = get_array_type(ira->codegen, slice_child_type, field_count, nullptr); - Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, slice_array_type); - if (type_is_invalid(res->value->type)) - return ira->codegen->invalid_inst_gen; - if (res->value->type->id != ZigTypeIdPointer) - res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - - return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr); - } else if (!slice_type->data.pointer.is_const && actual_type->data.pointer.is_const && field_count != 0) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to slice type '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - } - } - - // cast from undefined to anything - if (actual_type->id == ZigTypeIdUndefined) { - return ir_analyze_undefined_to_anything(ira, scope, source_node, value, wanted_type); - } - - // T to ?U, where T implicitly casts to U - if (wanted_type->id == ZigTypeIdOptional && actual_type->id != ZigTypeIdOptional) { - Stage1AirInst *cast1 = ir_implicit_cast2(ira, scope, source_node, value, wanted_type->data.maybe.child_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, scope, source_node, cast1, wanted_type); - } - - // T to E!U, where T implicitly casts to U - if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id != ZigTypeIdErrorUnion && - actual_type->id != ZigTypeIdErrorSet) - { - Stage1AirInst *cast1 = ir_implicit_cast2(ira, scope, source_node, value, wanted_type->data.error_union.payload_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, scope, source_node, cast1, wanted_type); - } - - // E!T to T - if (actual_type->id == ZigTypeIdErrorUnion) { - if (types_match_const_cast_only(ira, actual_type->data.error_union.payload_type, wanted_type, - source_node, false).id == ConstCastResultIdOk) - { - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; - } - } - - //?T to T - if (actual_type->id == ZigTypeIdOptional) { - if (types_match_const_cast_only(ira, actual_type->data.maybe.child_type, wanted_type, - source_node, false).id == ConstCastResultIdOk) - { - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; - } - } - - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_implicit_cast2(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *expected_type) -{ - assert(value); - assert(!expected_type || !type_is_invalid(expected_type)); - assert(value->value->type); - assert(!type_is_invalid(value->value->type)); - if (expected_type == nullptr) - return value; // anything will do - if (expected_type == value->value->type) - return value; // match - if (value->value->type->id == ZigTypeIdUnreachable) - return value; - - return ir_analyze_cast(ira, scope, source_node, expected_type, value); -} - -static Stage1AirInst *ir_implicit_cast(IrAnalyze *ira, Stage1AirInst *value, ZigType *expected_type) { - return ir_implicit_cast2(ira, value->scope, value->source_node, value, expected_type); -} - -static ZigType *get_ptr_elem_type(CodeGen *g, Stage1AirInst *ptr) { - ir_assert(ptr->value->type->id == ZigTypeIdPointer, ptr); - ZigType *elem_type = ptr->value->type->data.pointer.child_type; - if (elem_type != g->builtin_types.entry_anytype) - return elem_type; - - if (ir_resolve_lazy(g, ptr->source_node, ptr->value)) - return g->builtin_types.entry_invalid; - - assert(value_is_comptime(ptr->value)); - ZigValue *pointee = const_ptr_pointee_unchecked(g, ptr->value); - return pointee->type; -} - -static Stage1AirInst *ir_get_deref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, - ResultLoc *result_loc) -{ - Error err; - ZigType *ptr_type = ptr->value->type; - if (type_is_invalid(ptr_type)) - return ira->codegen->invalid_inst_gen; - - if (ptr_type->id != ZigTypeIdPointer) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = ptr_type->data.pointer.child_type; - if (type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen; - // if the child type has one possible value, the deref is comptime - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, scope, source_node, - get_the_one_possible_value(ira->codegen, child_type)); - case OnePossibleValueNo: - break; - } - if (instr_is_comptime(ptr)) { - if (ptr->value->special == ConstValSpecialUndef) { - // If we are in a TypeOf call, we return an undefined value instead of erroring - // since we know the type. - if (get_scope_typeof(scope)) { - return ir_const_undef(ira, scope, source_node, child_type); - } - - ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); - return ira->codegen->invalid_inst_gen; - } - if (ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr->value); - if (child_type == ira->codegen->builtin_types.entry_anytype) { - child_type = pointee->type; - } - if (pointee->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, child_type); - - if ((err = ir_read_const_ptr(ira, ira->codegen, source_node, result->value, - ptr->value))) - { - return ira->codegen->invalid_inst_gen; - } - result->value->type = child_type; - return result; - } - } - } - - // if the instruction is a const ref instruction we can skip it - if (ptr->id == Stage1AirInstIdRef) { - Stage1AirInstRef *ref_inst = reinterpret_cast(ptr); - return ref_inst->operand; - } - - // If the instruction is a element pointer instruction to a vector, we emit - // vector element extract instruction rather than load pointer. If the - // pointer type has non-VECTOR_INDEX_RUNTIME value, it would have been - // possible to implement this in the codegen for Stage1AirInstLoadPtr. - // However if it has VECTOR_INDEX_RUNTIME then we must emit a compile error - // if the vector index cannot be determined right here, right now, because - // the type information does not contain enough information to actually - // perform a dereference. - if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - if (ptr->id == Stage1AirInstIdElemPtr) { - Stage1AirInstElemPtr *elem_ptr = (Stage1AirInstElemPtr *)ptr; - Stage1AirInst *vector_loaded = ir_get_deref(ira, elem_ptr->array_ptr->scope, - elem_ptr->array_ptr->source_node, elem_ptr->array_ptr, nullptr); - Stage1AirInst *elem_index = elem_ptr->elem_index; - return ir_build_vector_extract_elem(ira, scope, source_node, vector_loaded, elem_index); - } - ir_add_error(ira, ptr, - buf_sprintf("unable to determine vector element index of type '%s'", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result_loc_inst; - if (ptr_type->data.pointer.host_int_bytes != 0 && handle_is_ptr(ira->codegen, child_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, child_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - return ir_build_load_ptr_gen(ira, scope, source_node, ptr, child_type, result_loc_inst); -} - -static bool ir_resolve_const_align(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *const_val, uint32_t *out) -{ - Error err; - if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad))) - return false; - - uint32_t align_bytes = bigint_as_u32(&const_val->data.x_bigint); - if (align_bytes == 0) { - exec_add_error_node_gen(codegen, exec, source_node, buf_sprintf("alignment must be >= 1")); - return false; - } - - if (!is_power_of_2(align_bytes)) { - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); - return false; - } - - *out = align_bytes; - return true; -} - -static bool ir_resolve_align(IrAnalyze *ira, Stage1AirInst *value, ZigType *elem_type, uint32_t *out) { - if (type_is_invalid(value->value->type)) - return false; - - // Look for this pattern: `*align(@alignOf(T)) T`. - // This can be resolved to be `*out = 0` without resolving any alignment. - if (elem_type != nullptr && value->value->special == ConstValSpecialLazy && - value->value->data.x_lazy->id == LazyValueIdAlignOf) - { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(value->value->data.x_lazy); - - ZigType *lazy_elem_type = ir_resolve_type(lazy_align_of->ira, lazy_align_of->target_type); - if (type_is_invalid(lazy_elem_type)) - return false; - - if (elem_type == lazy_elem_type) { - *out = 0; - return true; - } - } - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); - if (type_is_invalid(casted_value->value->type)) - return false; - - return ir_resolve_const_align(ira->codegen, ira->new_irb.exec, value->source_node, - casted_value->value, out); -} - -static bool ir_resolve_unsigned(IrAnalyze *ira, Stage1AirInst *value, ZigType *int_type, uint64_t *out) { - if (type_is_invalid(value->value->type)) - return false; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, int_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = bigint_as_u64(&const_val->data.x_bigint); - return true; -} - -static bool ir_resolve_usize(IrAnalyze *ira, Stage1AirInst *value, uint64_t *out) { - return ir_resolve_unsigned(ira, value, ira->codegen->builtin_types.entry_usize, out); -} - -static bool ir_resolve_bool(IrAnalyze *ira, Stage1AirInst *value, bool *out) { - if (type_is_invalid(value->value->type)) - return false; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_bool); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = const_val->data.x_bool; - return true; -} - -static bool ir_resolve_comptime(IrAnalyze *ira, Stage1AirInst *value, bool *out) { - if (!value) { - *out = false; - return true; - } - return ir_resolve_bool(ira, value, out); -} - -static bool ir_resolve_reduce_op(IrAnalyze *ira, Stage1AirInst *value, ReduceOp *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *reduce_op_type = get_builtin_type(ira->codegen, "ReduceOp"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, reduce_op_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (ReduceOp)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_atomic_order(IrAnalyze *ira, Stage1AirInst *value, AtomicOrder *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *atomic_order_type = get_builtin_type(ira->codegen, "AtomicOrder"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, atomic_order_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AtomicOrder)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, Stage1AirInst *value, AtomicRmwOp *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *atomic_rmw_op_type = get_builtin_type(ira->codegen, "AtomicRmwOp"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, atomic_rmw_op_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AtomicRmwOp)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_global_linkage(IrAnalyze *ira, Stage1AirInst *value, GlobalLinkageId *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *global_linkage_type = get_builtin_type(ira->codegen, "GlobalLinkage"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, global_linkage_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (GlobalLinkageId)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_float_mode(IrAnalyze *ira, Stage1AirInst *value, FloatMode *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *float_mode_type = get_builtin_type(ira->codegen, "FloatMode"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, float_mode_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (FloatMode)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static Buf *ir_resolve_str(IrAnalyze *ira, Stage1AirInst *value) { - if (type_is_invalid(value->value->type)) - return nullptr; - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(ira->codegen, ptr_type); - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, str_type); - if (type_is_invalid(casted_value->value->type)) - return nullptr; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return nullptr; - - ZigValue *ptr_field = const_val->data.x_struct.fields[slice_ptr_index]; - ZigValue *len_field = const_val->data.x_struct.fields[slice_len_index]; - - assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - size_t len = bigint_as_usize(&len_field->data.x_bigint); - if (array_val->data.x_array.special == ConstArraySpecialBuf && len == buf_len(array_val->data.x_array.data.s_buf)) { - return array_val->data.x_array.data.s_buf; - } - Buf *result = buf_alloc(); - buf_resize(result, len); - for (size_t i = 0; i < len; i += 1) { - size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; - ZigValue *char_val = &array_val->data.x_array.data.s_none.elements[new_index]; - if (char_val->special == ConstValSpecialUndef) { - ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); - return nullptr; - } - uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); - assert(big_c <= UINT8_MAX); - uint8_t c = (uint8_t)big_c; - buf_ptr(result)[i] = c; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, - Stage1ZirInstAddImplicitReturnType *instruction) -{ - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ir_unreach_error(ira); - - if (instruction->result_loc_ret == nullptr || !instruction->result_loc_ret->implicit_return_type_done) { - ira->src_implicit_return_type_list.append(value); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_return(IrAnalyze *ira, Stage1ZirInstReturn *instruction) { - if (instruction->operand == nullptr) { - // result location mechanism took care of it. - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, nullptr); - return ir_finish_anal(ira, result); - } - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type); - if (type_is_invalid(casted_operand->value->type)) { - AstNode *source_node = ira->explicit_return_type_source_node; - if (source_node != nullptr) { - ErrorMsg *msg = ira->codegen->errors.last(); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("return type declared here")); - } - return ir_unreach_error(ira); - } - - if (!instr_is_comptime(operand) && ira->explicit_return_type != nullptr && - handle_is_ptr(ira->codegen, ira->explicit_return_type)) - { - // result location mechanism took care of it. - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, nullptr); - return ir_finish_anal(ira, result); - } - - if (casted_operand->value->special == ConstValSpecialRuntime && - casted_operand->value->type->id == ZigTypeIdPointer && - casted_operand->value->data.rh_ptr == RuntimeHintPtrStack) - { - ir_add_error_node(ira, instruction->operand->source_node, - buf_sprintf("function returns address of local variable")); - return ir_unreach_error(ira); - } - - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, casted_operand); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_const(IrAnalyze *ira, Stage1ZirInstConst *instruction) { - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, instruction->value); -} - -static Stage1AirInst *ir_analyze_bin_op_bool(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, bool_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, bool_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - assert(casted_op1->value->type->id == ZigTypeIdBool); - assert(casted_op2->value->type->id == ZigTypeIdBool); - bool result_bool; - if (bin_op_instruction->op_id == IrBinOpBoolOr) { - result_bool = op1_val->data.x_bool || op2_val->data.x_bool; - } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) { - result_bool = op1_val->data.x_bool && op2_val->data.x_bool; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, result_bool); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, bool_type, bin_op_instruction->op_id, - casted_op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { - switch (op_id) { - case IrBinOpCmpEq: - return cmp == CmpEQ; - case IrBinOpCmpNotEq: - return cmp != CmpEQ; - case IrBinOpCmpLessThan: - return cmp == CmpLT; - case IrBinOpCmpGreaterThan: - return cmp == CmpGT; - case IrBinOpCmpLessOrEq: - return cmp != CmpGT; - case IrBinOpCmpGreaterOrEq: - return cmp != CmpLT; - default: - zig_unreachable(); - } -} - -static void set_optional_value_to_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (val->type->id == ZigTypeIdNull) return; // nothing to do - assert(val->type->id == ZigTypeIdOptional); - if (get_src_ptr_type(val->type) != nullptr) { - val->data.x_ptr.special = ConstPtrSpecialNull; - } else if (is_opt_err_set(val->type)) { - val->data.x_err_set = nullptr; - } else { - val->data.x_optional = nullptr; - } -} - -static void set_optional_payload(ZigValue *opt_val, ZigValue *payload) { - assert(opt_val->special == ConstValSpecialStatic); - assert(opt_val->type->id == ZigTypeIdOptional); - if (payload == nullptr) { - set_optional_value_to_null(opt_val); - } else if (get_src_ptr_type(opt_val->type)) { - assert(get_src_ptr_type(payload->type)); - opt_val->data.x_ptr = payload->data.x_ptr; - } else if (is_opt_err_set(opt_val->type)) { - assert(payload->type->id == ZigTypeIdErrorSet); - opt_val->data.x_err_set = payload->data.x_err_set; - } else { - opt_val->data.x_optional = payload; - } -} - -static Stage1AirInst *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type, - ZigValue *op1_val, ZigValue *op2_val, Scope *scope, AstNode *source_node, IrBinOp op_id, - bool one_possible_value) -{ - if (op1_val->special == ConstValSpecialUndef || - op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, resolved_type); - if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { - if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op1_val->data.x_ptr.special == ConstPtrSpecialNull) && - (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op2_val->data.x_ptr.special == ConstPtrSpecialNull)) - { - uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? - 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? - 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; - Cmp cmp_result; - if (op1_addr > op2_addr) { - cmp_result = CmpGT; - } else if (op1_addr < op2_addr) { - cmp_result = CmpLT; - } else { - cmp_result = CmpEQ; - } - bool answer = resolve_cmp_op_id(op_id, cmp_result); - return ir_const_bool(ira, scope, source_node, answer); - } - } else { - bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, scope, source_node, answer); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_try_evaluate_bin_op_cmp_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *op1, Stage1AirInst *op2, - ZigType *resolved_type, IrBinOp op_id) -{ - assert(op1->value->type == resolved_type && op2->value->type == resolved_type); - bool one_possible_value; - switch (type_has_one_possible_value(ira->codegen, resolved_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - one_possible_value = true; - break; - case OnePossibleValueNo: - one_possible_value = false; - break; - } - - if (one_possible_value || (instr_is_comptime(op1) && instr_is_comptime(op2))) { - ZigValue *op1_val = one_possible_value ? op1->value : ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_val = one_possible_value ? op2->value : ir_resolve_const(ira, op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (resolved_type->id != ZigTypeIdVector) - return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, scope, source_node, op_id, one_possible_value); - Stage1AirInst *result = ir_const(ira, scope, source_node, - get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool)); - result->value->data.x_array.data.s_none.elements = - ira->codegen->pass1_arena->allocate(resolved_type->data.vector.len); - - expand_undef_array(ira->codegen, result->value); - for (size_t i = 0;i < resolved_type->data.vector.len;i++) { - Stage1AirInst *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type, - &op1_val->data.x_array.data.s_none.elements[i], - &op2_val->data.x_array.data.s_none.elements[i], - scope, source_node, op_id, one_possible_value); - copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], cur_res->value); - } - return result; - } else { - return nullptr; - } -} - -// Returns ErrorNotLazy when the value cannot be determined -static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val, Cmp *result) { - Error err; - - switch (type_has_one_possible_value(codegen, val->type)) { - case OnePossibleValueInvalid: - return ErrorSemanticAnalyzeFail; - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - switch (val->type->id) { - case ZigTypeIdInt: - src_assert(val->type->data.integral.bit_count == 0, source_node); - *result = CmpEQ; - return ErrorNone; - case ZigTypeIdUndefined: - return ErrorNotLazy; - default: - zig_unreachable(); - } - } - - switch (val->special) { - case ConstValSpecialRuntime: - case ConstValSpecialUndef: - return ErrorNotLazy; - case ConstValSpecialStatic: - switch (val->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - *result = bigint_cmp_zero(&val->data.x_bigint); - return ErrorNone; - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: - if (float_is_nan(val)) - return ErrorNotLazy; - *result = float_cmp_zero(val); - return ErrorNone; - default: - return ErrorNotLazy; - } - case ConstValSpecialLazy: - switch (val->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - case LazyValueIdAlignOf: { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_align_of->ira; - - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_align_of->target_type->value, - nullptr, nullptr, &is_zero_bits))) - { - return err; - } - - *result = is_zero_bits ? CmpEQ : CmpGT; - return ErrorNone; - } - case LazyValueIdSizeOf: { - LazyValueSizeOf *lazy_size_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_size_of->ira; - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_size_of->target_type->value, - nullptr, nullptr, &is_zero_bits))) - { - return err; - } - *result = is_zero_bits ? CmpEQ : CmpGT; - return ErrorNone; - } - default: - return ErrorNotLazy; - } - } - zig_unreachable(); -} - -static ErrorMsg *ir_eval_bin_op_cmp_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val, ZigValue *out_val) -{ - Error err; - { - // Before resolving the values, we special case comparisons against zero. These can often - // be done without resolving lazy values, preventing potential dependency loops. - Cmp op1_cmp_zero; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op1_val, &op1_cmp_zero))) { - if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; - return ira->codegen->trace_err; - } - Cmp op2_cmp_zero; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op2_val, &op2_cmp_zero))) { - if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; - return ira->codegen->trace_err; - } - bool can_cmp_zero = false; - Cmp cmp_result; - if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpEQ; - } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpGT; - } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) { - can_cmp_zero = true; - cmp_result = CmpGT; - } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) { - can_cmp_zero = true; - cmp_result = CmpGT; - } - if (can_cmp_zero) { - bool answer = resolve_cmp_op_id(op_id, cmp_result); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = answer; - return nullptr; - } - } -never_mind_just_calculate_it_normally: - - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, - op1_val, UndefOk))) - { - return ira->codegen->trace_err; - } - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, - op2_val, UndefOk))) - { - return ira->codegen->trace_err; - } - - - if (op1_val->special == ConstValSpecialUndef || op2_val->special == ConstValSpecialUndef || - op1_val->type->id == ZigTypeIdUndefined || op2_val->type->id == ZigTypeIdUndefined) - { - out_val->special = ConstValSpecialUndef; - return nullptr; - } - - bool op1_is_float = op1_val->type->id == ZigTypeIdFloat || op1_val->type->id == ZigTypeIdComptimeFloat; - bool op2_is_float = op2_val->type->id == ZigTypeIdFloat || op2_val->type->id == ZigTypeIdComptimeFloat; - if (op1_is_float && op2_is_float) { - if (float_is_nan(op1_val) || float_is_nan(op2_val)) { - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = op_id == IrBinOpCmpNotEq; - return nullptr; - } - if (op1_val->type->id == ZigTypeIdComptimeFloat) { - Stage1AirInst *tmp = ir_const_noval(ira, scope, source_node); - tmp->value = op1_val; - Stage1AirInst *casted = ir_implicit_cast(ira, tmp, op2_val->type); - op1_val = casted->value; - } else if (op2_val->type->id == ZigTypeIdComptimeFloat) { - Stage1AirInst *tmp = ir_const_noval(ira, scope, source_node); - tmp->value = op2_val; - Stage1AirInst *casted = ir_implicit_cast(ira, tmp, op1_val->type); - op2_val = casted->value; - } - Cmp cmp_result = float_cmp(op1_val, op2_val); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - return nullptr; - } - - bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt; - bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt; - - if (op1_is_int && op2_is_int) { - Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - - return nullptr; - } - - // Handle the case where one of the two operands is a fp value and the other - // is an integer value - ZigValue *float_val; - if (op1_is_int && op2_is_float) { - float_val = op2_val; - } else if (op1_is_float && op2_is_int) { - float_val = op1_val; - } else { - zig_unreachable(); - } - - // They can never be equal if the fp value has a non-zero decimal part - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - if (float_has_fraction(float_val)) { - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = op_id == IrBinOpCmpNotEq; - return nullptr; - } - } - - // Cast the integer operand into a fp value to perform the comparison - BigFloat op1_bigfloat; - BigFloat op2_bigfloat; - value_to_bigfloat(&op1_bigfloat, op1_val); - value_to_bigfloat(&op2_bigfloat, op2_val); - - Cmp cmp_result = bigfloat_cmp(&op1_bigfloat, &op2_bigfloat); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - - return nullptr; -} - -static Stage1AirInst *ir_analyze_bin_op_cmp_numeric(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2, IrBinOp op_id) -{ - Error err; - - ZigType *scalar_result_type = ira->codegen->builtin_types.entry_bool; - ZigType *result_type = scalar_result_type; - ZigType *op1_scalar_type = op1->value->type; - ZigType *op2_scalar_type = op2->value->type; - if (op1->value->type->id == ZigTypeIdVector && op2->value->type->id == ZigTypeIdVector) { - if (op1->value->type->data.vector.len != op2->value->type->data.vector.len) { - ir_add_error_node(ira, source_node, - buf_sprintf("vector length mismatch: %" PRIu64 " and %" PRIu64, - op1->value->type->data.vector.len, op2->value->type->data.vector.len)); - return ira->codegen->invalid_inst_gen; - } - result_type = get_vector_type(ira->codegen, op1->value->type->data.vector.len, scalar_result_type); - op1_scalar_type = op1->value->type->data.vector.elem_type; - op2_scalar_type = op2->value->type->data.vector.elem_type; - } else if (op1->value->type->id == ZigTypeIdVector || op2->value->type->id == ZigTypeIdVector) { - ir_add_error_node(ira, source_node, - buf_sprintf("mixed scalar and vector operands to comparison operator: '%s' and '%s'", - buf_ptr(&op1->value->type->name), buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool opv_op1; - switch (type_has_one_possible_value(ira->codegen, op1->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - opv_op1 = true; - break; - case OnePossibleValueNo: - opv_op1 = false; - break; - } - bool opv_op2; - switch (type_has_one_possible_value(ira->codegen, op2->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - opv_op2 = true; - break; - case OnePossibleValueNo: - opv_op2 = false; - break; - } - Cmp op1_cmp_zero; - bool have_op1_cmp_zero = false; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op1->value, &op1_cmp_zero))) { - if (err != ErrorNotLazy) return ira->codegen->invalid_inst_gen; - } else { - have_op1_cmp_zero = true; - } - Cmp op2_cmp_zero; - bool have_op2_cmp_zero = false; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op2->value, &op2_cmp_zero))) { - if (err != ErrorNotLazy) return ira->codegen->invalid_inst_gen; - } else { - have_op2_cmp_zero = true; - } - if (((opv_op1 || instr_is_comptime(op1)) && (opv_op2 || instr_is_comptime(op2))) || - (have_op1_cmp_zero && have_op2_cmp_zero)) - { - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, result_type); - ZigValue *out_val = result_instruction->value; - if (result_type->id == ZigTypeIdVector) { - size_t len = result_type->data.vector.len; - expand_undef_array(ira->codegen, op1->value); - expand_undef_array(ira->codegen, op2->value); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_op1_val = &op1->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_op2_val = &op2->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_out_val->type == scalar_result_type); - ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, - scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = result_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_bin_op_cmp_scalar(ira, scope, source_node, op1->value, op_id, - op2->value, out_val) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result_instruction; - } - - // If one operand has a comptime-known comparison with 0, and the other operand is unsigned, we might - // know the answer, depending on the operator. - // TODO make this work with vectors - if (have_op1_cmp_zero && op2_scalar_type->id == ZigTypeIdInt && !op2_scalar_type->data.integral.is_signed) { - if (op1_cmp_zero == CmpEQ) { - // 0 <= unsigned_x // true - // 0 > unsigned_x // false - switch (op_id) { - case IrBinOpCmpLessOrEq: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } else if (op1_cmp_zero == CmpLT) { - // -1 != unsigned_x // true - // -1 <= unsigned_x // true - // -1 < unsigned_x // true - // -1 == unsigned_x // false - // -1 >= unsigned_x // false - // -1 > unsigned_x // false - switch (op_id) { - case IrBinOpCmpNotEq: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpLessThan: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } - } - if (have_op2_cmp_zero && op1_scalar_type->id == ZigTypeIdInt && !op1_scalar_type->data.integral.is_signed) { - if (op2_cmp_zero == CmpEQ) { - // unsigned_x < 0 // false - // unsigned_x >= 0 // true - switch (op_id) { - case IrBinOpCmpLessThan: - return ir_const_bool(ira, scope, source_node, false); - case IrBinOpCmpGreaterOrEq: - return ir_const_bool(ira, scope, source_node, true); - default: - break; - } - } else if (op2_cmp_zero == CmpLT) { - // unsigned_x != -1 // true - // unsigned_x >= -1 // true - // unsigned_x > -1 // true - // unsigned_x == -1 // false - // unsigned_x < -1 // false - // unsigned_x <= -1 // false - switch (op_id) { - case IrBinOpCmpNotEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpLessOrEq: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } - } - - // It must be a runtime comparison. - // For floats, emit a float comparison instruction. - bool op1_is_float = op1_scalar_type->id == ZigTypeIdFloat || op1_scalar_type->id == ZigTypeIdComptimeFloat; - bool op2_is_float = op2_scalar_type->id == ZigTypeIdFloat || op2_scalar_type->id == ZigTypeIdComptimeFloat; - if (op1_is_float && op2_is_float) { - // Implicit cast the smaller one to the larger one. - ZigType *dest_scalar_type; - if (op1_scalar_type->id == ZigTypeIdComptimeFloat) { - dest_scalar_type = op2_scalar_type; - } else if (op2_scalar_type->id == ZigTypeIdComptimeFloat) { - dest_scalar_type = op1_scalar_type; - } else if (op1_scalar_type->data.floating.bit_count >= op2_scalar_type->data.floating.bit_count) { - dest_scalar_type = op1_scalar_type; - } else { - dest_scalar_type = op2_scalar_type; - } - ZigType *dest_type = (result_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type; - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, dest_type); - if (type_is_invalid(casted_op1->value->type) || type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, casted_op1, casted_op2, true); - } - - // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. - // For mixed signed and unsigned integers, implicit cast both operands to a signed - // integer with + 1 bit. - // For mixed floats and integers, extract the integer part from the float, cast that to - // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, - // add/subtract 1. - bool dest_int_is_signed = false; - if (have_op1_cmp_zero) { - if (op1_cmp_zero == CmpLT) dest_int_is_signed = true; - } else if (op1_is_float) { - dest_int_is_signed = true; - } else if (op1_scalar_type->id == ZigTypeIdInt && op1_scalar_type->data.integral.is_signed) { - dest_int_is_signed = true; - } - if (have_op2_cmp_zero) { - if (op2_cmp_zero == CmpLT) dest_int_is_signed = true; - } else if (op2_is_float) { - dest_int_is_signed = true; - } else if (op2->value->type->id == ZigTypeIdInt && op2->value->type->data.integral.is_signed) { - dest_int_is_signed = true; - } - ZigType *dest_float_type = nullptr; - uint32_t op1_bits; - if (instr_is_comptime(op1) && result_type->id != ZigTypeIdVector) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefOk); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op1_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_unsigned; - if (op1_is_float) { - BigInt bigint = {}; - float_init_bigint(&bigint, op1_val); - Cmp zcmp = float_cmp_zero(op1_val); - if (float_has_fraction(op1_val)) { - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - return ir_const_bool(ira, scope, source_node, op_id == IrBinOpCmpNotEq); - } - if (zcmp == CmpLT) { - bigint_decr(&bigint); - } else { - bigint_incr(&bigint); - } - } - op1_bits = bigint_bits_needed(&bigint); - is_unsigned = zcmp != CmpLT; - } else { - op1_bits = bigint_bits_needed(&op1_val->data.x_bigint); - is_unsigned = bigint_cmp_zero(&op1_val->data.x_bigint) != CmpLT; - } - if (is_unsigned && dest_int_is_signed) { - op1_bits += 1; - } - } else if (op1_is_float) { - src_assert(op1_scalar_type->id == ZigTypeIdFloat, source_node); - dest_float_type = op1_scalar_type; - } else { - src_assert(op1_scalar_type->id == ZigTypeIdInt, source_node); - op1_bits = op1_scalar_type->data.integral.bit_count; - if (!op1_scalar_type->data.integral.is_signed && dest_int_is_signed) { - op1_bits += 1; - } - } - uint32_t op2_bits; - if (instr_is_comptime(op2) && result_type->id != ZigTypeIdVector) { - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefOk); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_unsigned; - if (op2_is_float) { - BigInt bigint = {}; - float_init_bigint(&bigint, op2_val); - Cmp zcmp = float_cmp_zero(op2_val); - if (float_has_fraction(op2_val)) { - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - return ir_const_bool(ira, scope, source_node, op_id == IrBinOpCmpNotEq); - } - if (zcmp == CmpLT) { - bigint_decr(&bigint); - } else { - bigint_incr(&bigint); - } - } - op2_bits = bigint_bits_needed(&bigint); - is_unsigned = zcmp != CmpLT; - } else { - op2_bits = bigint_bits_needed(&op2_val->data.x_bigint); - is_unsigned = bigint_cmp_zero(&op2_val->data.x_bigint) != CmpLT; - } - if (is_unsigned && dest_int_is_signed) { - op2_bits += 1; - } - } else if (op2_is_float) { - src_assert(op2_scalar_type->id == ZigTypeIdFloat, source_node); - dest_float_type = op2_scalar_type; - } else { - src_assert(op2_scalar_type->id == ZigTypeIdInt, source_node); - op2_bits = op2_scalar_type->data.integral.bit_count; - if (!op2_scalar_type->data.integral.is_signed && dest_int_is_signed) { - op2_bits += 1; - } - } - ZigType *dest_scalar_type = (dest_float_type == nullptr) ? - get_int_type(ira->codegen, dest_int_is_signed, (op1_bits > op2_bits) ? op1_bits : op2_bits) : - dest_float_type; - ZigType *dest_type = (result_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, dest_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, casted_op1, casted_op2, true); -} - -static bool type_is_self_comparable(ZigType *ty, bool is_equality_cmp) { - if (type_is_numeric(ty)) { - return true; - } - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - case ZigTypeIdFloat: - zig_unreachable(); // handled with the type_is_numeric check above - - case ZigTypeIdVector: - // Not every case is handled by the type_is_numeric check above, - // vectors of bool trigger this code path - case ZigTypeIdBool: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdEnum: - case ZigTypeIdEnumLiteral: - case ZigTypeIdAnyFrame: - return is_equality_cmp; - - case ZigTypeIdPointer: - return is_equality_cmp || (ty->data.pointer.ptr_len == PtrLenC); - - case ZigTypeIdUnreachable: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdUnion: - case ZigTypeIdFnFrame: - return false; - - case ZigTypeIdOptional: - return is_equality_cmp && get_src_ptr_type(ty) != nullptr; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_try_evaluate_cmp_optional_non_optional_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *child_type, - Stage1AirInst *optional, Stage1AirInst *non_optional, IrBinOp op_id) -{ - assert(optional->value->type->id == ZigTypeIdOptional); - assert(optional->value->type->data.maybe.child_type == non_optional->value->type); - assert(non_optional->value->type == child_type); - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - - if (instr_is_comptime(optional) && instr_is_comptime(non_optional)) { - ZigValue *optional_val = ir_resolve_const(ira, optional, UndefBad); - if (!optional_val) { - return ira->codegen->invalid_inst_gen; - } - - ZigValue *non_optional_val = ir_resolve_const(ira, non_optional, UndefBad); - if (!non_optional_val) { - return ira->codegen->invalid_inst_gen; - } - - if (!optional_value_is_null(optional_val)) { - Stage1AirInst *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, scope, source_node, optional, false); - if (type_is_invalid(optional_unwrapped->value->type)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *ret = ir_try_evaluate_bin_op_cmp_const(ira, scope, source_node, optional_unwrapped, non_optional, child_type, op_id); - assert(ret != nullptr); - return ret; - } - return ir_const_bool(ira, scope, source_node, (op_id != IrBinOpCmpEq)); - } else { - return nullptr; - } -} - -static Stage1AirInst *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *child_type, - Stage1AirInst *optional, Stage1AirInst *non_optional, IrBinOp op_id) -{ - assert(optional->value->type->id == ZigTypeIdOptional); - assert(optional->value->type->data.maybe.child_type == non_optional->value->type); - assert(non_optional->value->type == child_type); - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - - ZigType *result_type = ira->codegen->builtin_types.entry_bool; - ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block); - - Stage1AirBasicBlock *null_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalOptionalNull"); - Stage1AirBasicBlock *non_null_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalOptionalNotNull"); - Stage1AirBasicBlock *end_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalEnd"); - - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, scope, source_node, optional); - ir_build_cond_br_gen(ira, scope, source_node, is_non_null, non_null_block, null_block); - - ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, non_null_block); - Stage1AirInst *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, scope, source_node, optional, false); - if (type_is_invalid(optional_unwrapped->value->type)) { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *non_null_cmp_result = ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, - optional_unwrapped, non_optional, false); // safety check unnecessary for comparison operators - ir_build_br_gen(ira, scope, source_node, end_block); - - - ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, null_block); - Stage1AirInst *null_result = ir_const_bool(ira, scope, source_node, (op_id != IrBinOpCmpEq)); - ir_build_br_gen(ira, scope, source_node, end_block); - - ir_set_cursor_at_end_gen(&ira->new_irb, end_block); - int incoming_count = 2; - Stage1AirBasicBlock **incoming_blocks = heap::c_allocator.allocate_nonzero(incoming_count); - incoming_blocks[0] = null_block; - incoming_blocks[1] = non_null_block; - Stage1AirInst **incoming_values = heap::c_allocator.allocate_nonzero(incoming_count); - incoming_values[0] = null_result; - incoming_values[1] = non_null_cmp_result; - - const bool merge_comptime = false; - return ir_build_phi_gen(ira, scope, source_node, merge_comptime, incoming_count, incoming_blocks, incoming_values, result_type); -} - -static Stage1AirInst *ir_analyze_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2, Stage1AirInst *optional, IrBinOp op_id) -{ - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - assert(optional->value->type->id == ZigTypeIdOptional); - assert(get_src_ptr_type(optional->value->type) == nullptr); - - Stage1AirInst *non_optional; - if (op1 == optional) { - non_optional = op2; - } else if (op2 == optional) { - non_optional = op1; - } else { - zig_unreachable(); - } - - ZigType *child_type = optional->value->type->data.maybe.child_type; - bool child_type_matches = (child_type == non_optional->value->type); - if (!child_type_matches || !type_is_self_comparable(child_type, true)) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cannot compare types '%s' and '%s'", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - - if (!child_type_matches) { - if (non_optional->value->type->id == ZigTypeIdOptional) { - add_error_note(ira->codegen, msg, source_node, buf_sprintf( - "optional to optional comparison is only supported for optional pointer types")); - } else { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("optional child type '%s' must be the same as non-optional type '%s'", - buf_ptr(&child_type->name), - buf_ptr(&non_optional->value->type->name))); - } - } else { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("operator not supported for type '%s'", - buf_ptr(&child_type->name))); - } - return ira->codegen->invalid_inst_gen; - } - - if (child_type->id == ZigTypeIdVector) { - ir_add_error_node(ira, source_node, buf_sprintf("TODO add comparison of optional vector")); - return ira->codegen->invalid_inst_gen; - } - - if (Stage1AirInst *const_result = ir_try_evaluate_cmp_optional_non_optional_const(ira, scope, source_node, child_type, - optional, non_optional, op_id)) - { - return const_result; - } - - return ir_evaluate_cmp_optional_non_optional(ira, scope, source_node, child_type, optional, non_optional, op_id); -} - -static Stage1AirInst *ir_analyze_bin_op_cmp(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = bin_op_instruction->base.source_node; - - IrBinOp op_id = bin_op_instruction->op_id; - bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - if (is_equality_cmp && op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdNull) { - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, (op_id == IrBinOpCmpEq)); - } else if (is_equality_cmp && - ((op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdOptional) || - (op2->value->type->id == ZigTypeIdNull && op1->value->type->id == ZigTypeIdOptional))) - { - Stage1AirInst *maybe_op; - if (op1->value->type->id == ZigTypeIdNull) { - maybe_op = op2; - } else if (op2->value->type->id == ZigTypeIdNull) { - maybe_op = op1; - } else { - zig_unreachable(); - } - if (instr_is_comptime(maybe_op)) { - ZigValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad); - if (!maybe_val) - return ira->codegen->invalid_inst_gen; - bool is_null = optional_value_is_null(maybe_val); - bool bool_result = (op_id == IrBinOpCmpEq) ? is_null : !is_null; - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, bool_result); - } - - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, maybe_op); - - if (op_id == IrBinOpCmpEq) { - return ir_build_bool_not_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, is_non_null); - } else { - return is_non_null; - } - } else if (is_equality_cmp && - ((op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdPointer && - op2->value->type->data.pointer.ptr_len == PtrLenC) || - (op2->value->type->id == ZigTypeIdNull && op1->value->type->id == ZigTypeIdPointer && - op1->value->type->data.pointer.ptr_len == PtrLenC))) - { - Stage1AirInst *c_ptr_op; - if (op1->value->type->id == ZigTypeIdNull) { - c_ptr_op = op2; - } else if (op2->value->type->id == ZigTypeIdNull) { - c_ptr_op = op1; - } else { - zig_unreachable(); - } - if (instr_is_comptime(c_ptr_op)) { - ZigValue *c_ptr_val = ir_resolve_const(ira, c_ptr_op, UndefOk); - if (!c_ptr_val) - return ira->codegen->invalid_inst_gen; - if (c_ptr_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool); - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - bool bool_result = (op_id == IrBinOpCmpEq) ? is_null : !is_null; - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, bool_result); - } - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, c_ptr_op); - - if (op_id == IrBinOpCmpEq) { - return ir_build_bool_not_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, is_non_null); - } else { - return is_non_null; - } - } else if (is_equality_cmp && - (op1->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op1->value->type) == nullptr)) - { - return ir_analyze_cmp_optional_non_optional(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op1, op_id); - } else if(is_equality_cmp && - (op2->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op2->value->type) == nullptr)) - { - return ir_analyze_cmp_optional_non_optional(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op2, op_id); - } else if (op1->value->type->id == ZigTypeIdNull || op2->value->type->id == ZigTypeIdNull) { - ZigType *non_null_type = (op1->value->type->id == ZigTypeIdNull) ? op2->value->type : op1->value->type; - ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null", - buf_ptr(&non_null_type->name))); - return ira->codegen->invalid_inst_gen; - } else if (is_equality_cmp && ( - (op1->value->type->id == ZigTypeIdEnumLiteral && op2->value->type->id == ZigTypeIdUnion) || - (op2->value->type->id == ZigTypeIdEnumLiteral && op1->value->type->id == ZigTypeIdUnion))) - { - // Support equality comparison between a union's tag value and a enum literal - Stage1AirInst *union_val = op1->value->type->id == ZigTypeIdUnion ? op1 : op2; - Stage1AirInst *enum_val = op1->value->type->id == ZigTypeIdUnion ? op2 : op1; - - if (!is_tagged_union(union_val->value->type)) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("comparison of union and enum literal is only valid for tagged union types")); - add_error_note(ira->codegen, msg, union_val->value->type->data.unionation.decl_node, - buf_sprintf("type %s is not a tagged union", - buf_ptr(&union_val->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *tag_type = union_val->value->type->data.unionation.tag_type; - assert(tag_type != nullptr); - - Stage1AirInst *casted_union = ir_implicit_cast(ira, union_val, tag_type); - if (type_is_invalid(casted_union->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_val = ir_implicit_cast(ira, enum_val, tag_type); - if (type_is_invalid(casted_val->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_union)) { - ZigValue *const_union_val = ir_resolve_const(ira, casted_union, UndefBad); - if (!const_union_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_enum_val = ir_resolve_const(ira, casted_val, UndefBad); - if (!const_enum_val) - return ira->codegen->invalid_inst_gen; - - Cmp cmp_result = bigint_cmp(&const_union_val->data.x_union.tag, &const_enum_val->data.x_enum_tag); - bool bool_result = (op_id == IrBinOpCmpEq) ? cmp_result == CmpEQ : cmp_result != CmpEQ; - - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, bool_result); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool, - op_id, casted_union, casted_val, bin_op_instruction->safety_check_on); - } - - if (op1->value->type->id == ZigTypeIdErrorSet && op2->value->type->id == ZigTypeIdErrorSet) { - if (!is_equality_cmp) { - ir_add_error_node(ira, source_node, buf_sprintf("operator not allowed for errors")); - return ira->codegen->invalid_inst_gen; - } - ZigType *intersect_type = get_error_set_intersection(ira, op1->value->type, op2->value->type, source_node); - if (type_is_invalid(intersect_type)) { - return ira->codegen->invalid_inst_gen; - } - - if (!resolve_inferred_error_set(ira->codegen, intersect_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - - // exception if one of the operators has the type of the empty error set, we allow the comparison - // (and make it comptime known) - // this is a function which is evaluated at comptime and returns an inferred error set will have an empty - // error set. - if (op1->value->type->data.error_set.err_count == 0 || op2->value->type->data.error_set.err_count == 0) { - bool are_equal = false; - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - - if (!type_is_global_error_set(intersect_type)) { - if (intersect_type->data.error_set.err_count == 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("error sets '%s' and '%s' have no common errors", - buf_ptr(&op1->value->type->name), buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (op1->value->type->data.error_set.err_count == 1 && op2->value->type->data.error_set.err_count == 1) { - bool are_equal = true; - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - } - - if (instr_is_comptime(op1) && instr_is_comptime(op2)) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - bool answer; - bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool, - op_id, op1, op2, bin_op_instruction->safety_check_on); - } - - if (type_is_numeric(op1->value->type) && type_is_numeric(op2->value->type)) { - // This operation allows any combination of integer and float types, regardless of the - // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for - // numeric types. - return ir_analyze_bin_op_cmp_numeric(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op_id); - } - - Stage1AirInst *instructions[] = {op1, op2}; - ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - - bool operator_allowed = type_is_self_comparable(resolved_type, is_equality_cmp); - - if (!operator_allowed) { - ir_add_error_node(ira, source_node, - buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, resolved_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, resolved_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *resolve_const_result = ir_try_evaluate_bin_op_cmp_const(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, casted_op1, - casted_op2, resolved_type, op_id); - if (resolve_const_result != nullptr) { - return resolve_const_result; - } - - ZigType *res_type = (resolved_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool) : - ira->codegen->builtin_types.entry_bool; - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, res_type, - op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *type_entry, - ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val, ZigValue *out_val) -{ - bool is_int; - bool is_float; - Cmp op2_zcmp; - if (type_entry->id == ZigTypeIdInt || type_entry->id == ZigTypeIdComptimeInt) { - is_int = true; - is_float = false; - op2_zcmp = bigint_cmp_zero(&op2_val->data.x_bigint); - } else if (type_entry->id == ZigTypeIdFloat || - type_entry->id == ZigTypeIdComptimeFloat) - { - is_int = false; - is_float = true; - op2_zcmp = float_cmp_zero(op2_val); - } else { - zig_unreachable(); - } - - if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || - op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) - { - return ir_add_error_node(ira, source_node, buf_sprintf("division by zero")); - } - if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { - return ir_add_error_node(ira, source_node, buf_sprintf("negative denominator")); - } - - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - zig_unreachable(); - case IrBinOpBinOr: - assert(is_int); - bigint_or(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBinXor: - assert(is_int); - bigint_xor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBinAnd: - assert(is_int); - bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBitShiftLeftExact: - assert(is_int); - bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBitShiftLeftLossy: - assert(type_entry->id == ZigTypeIdInt); - bigint_shl_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpBitShiftRightExact: - { - assert(is_int); - bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - BigInt orig_bigint; - bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); - if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact shift shifted out 1 bits")); - } - break; - } - case IrBinOpBitShiftRightLossy: - assert(is_int); - bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpAdd: - if (is_int) { - bigint_add(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_add(out_val, op1_val, op2_val); - } - break; - case IrBinOpAddWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_add_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpSub: - if (is_int) { - bigint_sub(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_sub(out_val, op1_val, op2_val); - } - break; - case IrBinOpSubWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_sub_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpMult: - if (is_int) { - bigint_mul(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_mul(out_val, op1_val, op2_val); - } - break; - case IrBinOpMultWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_mul_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpDivUnspecified: - assert(is_float); - float_div(out_val, op1_val, op2_val); - break; - case IrBinOpDivTrunc: - if (is_int) { - bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_div_trunc(out_val, op1_val, op2_val); - } - break; - case IrBinOpDivFloor: - if (is_int) { - bigint_div_floor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_div_floor(out_val, op1_val, op2_val); - } - break; - case IrBinOpDivExact: - if (is_int) { - bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - BigInt remainder; - bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - if (bigint_cmp_zero(&remainder) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact division had a remainder")); - } - } else { - float_div_trunc(out_val, op1_val, op2_val); - ZigValue remainder = {}; - float_rem(&remainder, op1_val, op2_val); - if (float_cmp_zero(&remainder) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact division had a remainder")); - } - } - break; - case IrBinOpRemRem: - if (is_int) { - bigint_rem(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_rem(out_val, op1_val, op2_val); - } - break; - case IrBinOpRemMod: - if (is_int) { - bigint_mod(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_mod(out_val, op1_val, op2_val); - } - break; - case IrBinOpMax: - if (is_int) { - bigint_max(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_max(out_val, op1_val, op2_val); - } - break; - case IrBinOpMin: - if (is_int) { - bigint_min(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_min(out_val, op1_val, op2_val); - } - break; - case IrBinOpAddSat: - if (is_int) { - bigint_add_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpSubSat: - if (is_int) { - bigint_sub_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpMultSat: - if (is_int) { - bigint_mul_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpShlSat: - if (is_int) { - bigint_shl_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - } - - if (type_entry->id == ZigTypeIdInt) { - if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, - type_entry->data.integral.is_signed)) - { - return ir_add_error_node(ira, source_node, buf_sprintf("operation caused overflow")); - } - } - - out_val->type = type_entry; - out_val->special = ConstValSpecialStatic; - return nullptr; -} - -// This works on operands that have already been checked to be comptime known. -static Stage1AirInst *ir_analyze_math_op(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *type_entry, ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val) -{ - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, type_entry); - ZigValue *out_val = result_instruction->value; - if (type_entry->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op1_val); - expand_undef_array(ira->codegen, op2_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = type_entry->data.vector.len; - ZigType *scalar_type = type_entry->data.vector.elem_type; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_op1_val->type == scalar_type); - assert(scalar_out_val->type == scalar_type); - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = type_entry; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_math_op_scalar(ira, scope, source_node, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) { - return ira->codegen->invalid_inst_gen; - } - } - return ir_implicit_cast(ira, result_instruction, type_entry); -} - -static Stage1AirInst *ir_analyze_truncate(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_scalar_type, AstNode *dest_type_node, - Stage1AirInst *operand, AstNode *operand_node) -{ - if (dest_scalar_type->id != ZigTypeIdInt && - dest_scalar_type->id != ZigTypeIdComptimeInt) - { - ir_add_error_node(ira, dest_type_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *src_type = operand->value->type; - bool is_vector = (src_type->id == ZigTypeIdVector); - ZigType *src_scalar_type = is_vector ? - src_type->data.vector.elem_type : src_type; - - ZigType *dest_type = is_vector ? - get_vector_type(ira->codegen, src_type->data.vector.len, dest_scalar_type) : - dest_scalar_type; - - if (src_scalar_type->id != ZigTypeIdInt && src_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, operand_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (dest_scalar_type->id == ZigTypeIdComptimeInt) { - return ir_implicit_cast2(ira, scope, operand_node, operand, dest_type); - } - - if (src_scalar_type->id != ZigTypeIdComptimeInt) { - if (src_scalar_type->data.integral.is_signed != dest_scalar_type->data.integral.is_signed) { - const char *sign_str = dest_scalar_type->data.integral.is_signed ? "signed" : "unsigned"; - ir_add_error_node(ira, operand_node, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } else if (src_scalar_type->data.integral.bit_count > 0 && src_scalar_type->data.integral.bit_count < dest_scalar_type->data.integral.bit_count) { - ir_add_error_node(ira, operand_node, buf_sprintf("type '%s' has fewer bits than destination type '%s'", - buf_ptr(&src_scalar_type->name), buf_ptr(&dest_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (instr_is_comptime(operand)) { - ZigValue *val = ir_resolve_const(ira, operand, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!is_vector) { - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - bigint_truncate(&result->value->data.x_bigint, &val->data.x_bigint, - dest_scalar_type->data.integral.bit_count, - dest_scalar_type->data.integral.is_signed); - return result; - } - - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, dest_type); - ZigValue *out_val = result_instruction->value; - expand_undef_array(ira->codegen, operand->value); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = dest_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_operand_val = &operand->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_operand_val->type == dest_scalar_type); - assert(scalar_out_val->type == dest_scalar_type); - - bigint_truncate(&scalar_out_val->data.x_bigint, - &scalar_operand_val->data.x_bigint, - dest_scalar_type->data.integral.bit_count, - dest_scalar_type->data.integral.is_signed); - - scalar_out_val->type = dest_scalar_type; - scalar_out_val->special = ConstValSpecialStatic; - } - out_val->type = dest_type; - out_val->special = ConstValSpecialStatic; - return result_instruction; - } - - if (src_scalar_type->data.integral.bit_count == 0 || - dest_scalar_type->data.integral.bit_count == 0) - { - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - if (!is_vector) { - bigint_init_unsigned(&result->value->data.x_bigint, 0); - } - return result; - } - - return ir_build_truncate_gen(ira, scope, source_node, dest_type, operand); -} - -static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *op1_type = op1->value->type; - ZigType *op2_type = op2->value->type; - - if (op1_type->id == ZigTypeIdVector && op2_type->id != ZigTypeIdVector) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected vector type, found '%s'", - buf_ptr(&op2_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (op1_type->id != ZigTypeIdVector && op2_type->id == ZigTypeIdVector) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected vector type, found '%s'", - buf_ptr(&op1_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *op1_scalar_type = (op1_type->id == ZigTypeIdVector) ? - op1_type->data.vector.elem_type : op1_type; - ZigType *op2_scalar_type = (op2_type->id == ZigTypeIdVector) ? - op2_type->data.vector.elem_type : op2_type; - - if (op1_scalar_type->id != ZigTypeIdInt && op1_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected integer type, found '%s'", - buf_ptr(&op1_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (op2_scalar_type->id != ZigTypeIdInt && op2_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, bin_op_instruction->op2->source_node, - buf_sprintf("shift amount has to be an integer type, but found '%s'", - buf_ptr(&op2_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op2; - IrBinOp op_id = bin_op_instruction->op_id; - if (op1_scalar_type->id == ZigTypeIdComptimeInt) { - // comptime_int has no finite bit width - casted_op2 = op2; - - if (op_id == IrBinOpBitShiftLeftLossy || op_id == IrBinOpShlSat) { - op_id = IrBinOpBitShiftLeftExact; - } - - if (!instr_is_comptime(op2)) { - ir_add_error_node(ira, bin_op_instruction->base.source_node, - buf_sprintf("LHS of shift must be a fixed-width integer type, or RHS must be compile-time known")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (op2_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - } else if (op_id == IrBinOpShlSat) { - casted_op2 = ir_analyze_truncate(ira, - bin_op_instruction->base.scope, bin_op_instruction->base.source_node, - op1_scalar_type, bin_op_instruction->op1->source_node, - op2, bin_op_instruction->op2->source_node); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - const unsigned bit_count = op1_scalar_type->data.integral.bit_count; - ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - bit_count > 0 ? bit_count - 1 : 0); - - if (op1_type->id == ZigTypeIdVector) { - shift_amt_type = get_vector_type(ira->codegen, op1_type->data.vector.len, - shift_amt_type); - } - - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // This check is only valid iff op1 has at least one bit - if (bit_count > 0 && instr_is_comptime(casted_op2)) { - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue bit_count_value = {}; - init_const_usize(ira->codegen, &bit_count_value, bit_count); - - if (!value_cmp_numeric_val_all(op2_val, CmpLT, &bit_count_value)) { - ErrorMsg* msg = ir_add_error_node(ira, - bin_op_instruction->base.source_node, - buf_sprintf("RHS of shift is too large for LHS type")); - add_error_note(ira->codegen, msg, op1->source_node, - buf_sprintf("type %s has only %u bits", - buf_ptr(&op1->value->type->name), bit_count)); - - return ira->codegen->invalid_inst_gen; - } - } - } - - // Fast path for zero RHS - if (instr_is_comptime(casted_op2)) { - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (op2_val->type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op2_val); - size_t len = op2_val->type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_val = &op2_val->data.x_array.data.s_none.elements[i]; - if (scalar_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &scalar_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s at vector index %zu", - buf_ptr(val_buf), i)); - return ira->codegen->invalid_inst_gen; - } - } - } else { - if (op2_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - } - - if (value_cmp_numeric_val_all(op2_val, CmpEQ, nullptr)) - return ir_analyze_cast(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1->value->type, op1); - } - - if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_math_op(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1_type, op1_val, op_id, op2_val); - } - - return ir_build_bin_op_gen(ira, - bin_op_instruction->base.scope, bin_op_instruction->base.source_node, - op1->value->type, op_id, op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static bool ok_float_op(IrBinOp op) { - switch (op) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpAdd: - case IrBinOpSub: - case IrBinOpMult: - case IrBinOpDivUnspecified: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - case IrBinOpDivExact: - case IrBinOpRemRem: - case IrBinOpRemMod: - case IrBinOpRemUnspecified: - case IrBinOpMax: - case IrBinOpMin: - return true; - - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpAddWrap: - case IrBinOpSubWrap: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - case IrBinOpShlSat: - case IrBinOpMultWrap: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - return false; - } - zig_unreachable(); -} - -static IrBinOp map_comptime_arithmetic_op(IrBinOp op) { - switch (op) { - case IrBinOpAddWrap: - case IrBinOpAddSat: - return IrBinOpAdd; - - case IrBinOpSubWrap: - case IrBinOpSubSat: - return IrBinOpSub; - - case IrBinOpMultWrap: - case IrBinOpMultSat: - return IrBinOpMult; - - default: - return op; - } -} - -static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { - switch (op) { - case IrBinOpAdd: - case IrBinOpSub: - break; - default: - return false; - } - if (lhs_type->id != ZigTypeIdPointer) - return false; - switch (lhs_type->data.pointer.ptr_len) { - case PtrLenSingle: - return false; - case PtrLenUnknown: - case PtrLenC: - return true; - } - zig_unreachable(); -} - -// Returns true if integer `value` can be converted to `type_entry` without -// losing data. -// If `value` is a vector the function returns true if this is valid for every -// element. -static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry) { - assert(value->special == ConstValSpecialStatic); - assert(type_entry->id == ZigTypeIdInt); - - switch (value->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - return bigint_fits_in_bits(&value->data.x_bigint, type_entry->data.integral.bit_count, - type_entry->data.integral.is_signed); - } - case ZigTypeIdVector: { - for (size_t i = 0; i < value->type->data.vector.len; i++) { - ZigValue *scalar_value = &value->data.x_array.data.s_none.elements[i]; - const bool result = bigint_fits_in_bits(&scalar_value->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - if (!result) return false; - } - return true; - } - default: zig_unreachable(); - } -} - -static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) { - assert(left->special == ConstValSpecialStatic); - assert(right == nullptr || right->special == ConstValSpecialStatic); - - switch (left->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - const Cmp result = right ? - bigint_cmp(&left->data.x_bigint, &right->data.x_bigint) : - bigint_cmp_zero(&left->data.x_bigint); - return result == predicate; - } - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: { - if (float_is_nan(left)) - return false; - if (right != nullptr && float_is_nan(right)) - return false; - - const Cmp result = right ? float_cmp(left, right) : float_cmp_zero(left); - return result == predicate; - } - case ZigTypeIdVector: { - for (size_t i = 0; i < left->type->data.vector.len; i++) { - ZigValue *scalar_val = &left->data.x_array.data.s_none.elements[i]; - const bool result = value_cmp_numeric_val(scalar_val, predicate, right, any); - - if (any && result) - return true; // This element satisfies the predicate - else if (!any && !result) - return false; // This element doesn't satisfy the predicate - } - return any ? false : true; - } - default: - zig_unreachable(); - } -} - -static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right) { - return value_cmp_numeric_val(left, predicate, right, true); -} - -static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right) { - return value_cmp_numeric_val(left, predicate, right, false); -} - -static Stage1AirInst *ir_analyze_bin_op_math(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Error err; - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - IrBinOp op_id = instruction->op_id; - - // look for pointer math - if (is_pointer_arithmetic_allowed(op1->value->type, op_id)) { - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // If either operand is undef, result is undef. - ZigValue *op1_val = nullptr; - ZigValue *op2_val = nullptr; - if (instr_is_comptime(op1)) { - op1_val = ir_resolve_const(ira, op1, UndefOk); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op1_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op1->value->type); - } - if (instr_is_comptime(casted_op2)) { - op2_val = ir_resolve_const(ira, casted_op2, UndefOk); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op1->value->type); - } - - ZigType *elem_type = op1->value->type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - // NOTE: this variable is meaningful iff op2_val is not null! - uint64_t byte_offset; - if (op2_val != nullptr) { - uint64_t elem_offset; - if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) - return ira->codegen->invalid_inst_gen; - - byte_offset = type_size(ira->codegen, elem_type) * elem_offset; - } - - // Fast path for cases where the RHS is zero - if (op2_val != nullptr && byte_offset == 0) { - return op1; - } - - ZigType *result_type = op1->value->type; - // Calculate the new alignment of the pointer - { - uint32_t align_bytes; - if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes))) - return ira->codegen->invalid_inst_gen; - - // If the addend is not a comptime-known value we can still count on - // it being a multiple of the type size - uint32_t addend = op2_val ? byte_offset : type_size(ira->codegen, elem_type); - - // The resulting pointer is aligned to the lcd between the - // offset (an arbitrary number) and the alignment factor (always - // a power of two, non zero) - uint32_t new_align = 1 << ctzll(addend | align_bytes); - // Rough guard to prevent overflows - assert(new_align); - result_type = adjust_ptr_align(ira->codegen, result_type, new_align); - } - - if (op2_val != nullptr && op1_val != nullptr && - (op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op1->value->data.x_ptr.special == ConstPtrSpecialNull)) - { - uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? - 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t new_addr; - if (op_id == IrBinOpAdd) { - new_addr = start_addr + byte_offset; - } else if (op_id == IrBinOpSub) { - new_addr = start_addr - byte_offset; - } else { - zig_unreachable(); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - result->value->data.x_ptr.data.hard_coded_addr.addr = new_addr; - return result; - } - - return ir_build_bin_op_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, op_id, op1, casted_op2, true); - } - - Stage1AirInst *instructions[] = {op1, op2}; - ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *scalar_type = (resolved_type->id == ZigTypeIdVector) ? - resolved_type->data.vector.elem_type : resolved_type; - - bool is_int = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt; - bool is_float = scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat; - - if (!is_int && !(is_float && ok_float_op(op_id))) { - AstNode *source_node = instruction->base.source_node; - ir_add_error_node(ira, source_node, - buf_sprintf("invalid operands to binary expression: '%s' and '%s'", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, resolved_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, resolved_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // Comptime integers have no fixed size, so wrapping or saturating operations should be mapped - // to their non wrapping or saturating equivalents - if (scalar_type->id == ZigTypeIdComptimeInt) { - op_id = map_comptime_arithmetic_op(op_id); - } - - if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - // Promote division with negative numbers to signed - bool is_signed_div = value_cmp_numeric_val_any(op1_val, CmpLT, nullptr) || - value_cmp_numeric_val_any(op2_val, CmpLT, nullptr); - - if (op_id == IrBinOpDivUnspecified && is_int) { - // Default to truncating division and check if it's valid for the - // given operands if signed - op_id = IrBinOpDivTrunc; - - if (is_signed_div) { - bool ok = false; - - if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { - // the division by zero error will be caught later, but we don't have a - // division function ambiguity problem. - ok = true; - } else { - Stage1AirInst *trunc_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpDivTrunc, op2_val); - if (type_is_invalid(trunc_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *floor_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpDivFloor, op2_val); - if (type_is_invalid(floor_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_val = ir_analyze_bin_op_cmp_numeric(ira, instruction->base.scope, instruction->base.source_node, - trunc_val, floor_val, IrBinOpCmpEq); - if (type_is_invalid(cmp_val->value->type)) - return ira->codegen->invalid_inst_gen; - - // We can "upgrade" the operator only if trunc(a/b) == floor(a/b) - if (!ir_resolve_bool(ira, cmp_val, &ok)) - return ira->codegen->invalid_inst_gen; - } - - if (!ok) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - } else if (op_id == IrBinOpRemUnspecified) { - op_id = IrBinOpRemRem; - - if (is_signed_div) { - bool ok = false; - - if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { - // the division by zero error will be caught later, but we don't have a - // division function ambiguity problem. - ok = true; - } else { - Stage1AirInst *rem_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpRemRem, op2_val); - if (type_is_invalid(rem_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *mod_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpRemMod, op2_val); - if (type_is_invalid(mod_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_val = ir_analyze_bin_op_cmp_numeric(ira, instruction->base.scope, instruction->base.source_node, - rem_val, mod_val, IrBinOpCmpEq); - if (type_is_invalid(cmp_val->value->type)) - return ira->codegen->invalid_inst_gen; - - // We can "upgrade" the operator only if mod(a,b) == rem(a,b) - if (!ir_resolve_bool(ira, cmp_val, &ok)) - return ira->codegen->invalid_inst_gen; - } - - if (!ok) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - } - - return ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, op1_val, op_id, op2_val); - } - - const bool is_signed_div = - (scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) || - scalar_type->id == ZigTypeIdFloat; - - // Warn the user to use the proper operators here - if (op_id == IrBinOpDivUnspecified && is_int) { - op_id = IrBinOpDivTrunc; - - if (is_signed_div) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (op_id == IrBinOpRemUnspecified) { - op_id = IrBinOpRemRem; - - if (is_signed_div) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - return ir_build_bin_op_gen(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op_id, casted_op1, casted_op2, instruction->safety_check_on); -} - -static Stage1AirInst *ir_analyze_tuple_cat(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2) -{ - Error err; - ZigType *op1_type = op1->value->type; - ZigType *op2_type = op2->value->type; - - uint32_t op1_field_count = op1_type->data.structure.src_field_count; - uint32_t op2_field_count = op2_type->data.structure.src_field_count; - - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - scope, source_node, bare_name, nullptr); - ZigType *new_type = get_partial_container_type(ira->codegen, scope, - ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto); - new_type->data.structure.special = StructSpecialInferredTuple; - new_type->data.structure.resolve_status = ResolveStatusBeingInferred; - uint32_t new_field_count = op1_field_count + op2_field_count; - - new_type->data.structure.src_field_count = new_field_count; - new_type->data.structure.fields = realloc_type_struct_fields(new_type->data.structure.fields, - 0, new_field_count); - - Stage1AirInst *new_struct_ptr = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - new_type, nullptr, false, true); - - for (uint32_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field; - if (i < op1_field_count) { - src_field = op1_type->data.structure.fields[i]; - } else { - src_field = op2_type->data.structure.fields[i - op1_field_count]; - } - TypeStructField *new_field = new_type->data.structure.fields[i]; - new_field->name = buf_sprintf("%" PRIu32, i); - new_field->type_entry = src_field->type_entry; - new_field->type_val = src_field->type_val; - new_field->src_index = i; - new_field->decl_node = src_field->decl_node; - new_field->init_val = src_field->init_val; - new_field->is_comptime = src_field->is_comptime; - } - if ((err = type_resolve(ira->codegen, new_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigList const_ptrs = {}; - for (uint32_t i = 0; i < new_field_count; i += 1) { - TypeStructField *dst_field = new_type->data.structure.fields[i]; - Stage1AirInst *src_struct_op; - TypeStructField *src_field; - if (i < op1_field_count) { - src_field = op1_type->data.structure.fields[i]; - src_struct_op = op1; - } else { - src_field = op2_type->data.structure.fields[i - op1_field_count]; - src_struct_op = op2; - } - Stage1AirInst *field_value = ir_analyze_struct_value_field_value(ira, scope, source_node, - src_struct_op, src_field); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *dest_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, dst_field, - new_struct_ptr, new_type, true); - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - if (instr_is_comptime(field_value)) { - const_ptrs.append(dest_ptr); - } - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, dest_ptr, field_value, - true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - if (const_ptrs.length != new_field_count) { - new_struct_ptr->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - if (!type_requires_comptime(ira->codegen, elem_result_loc->value->type->data.pointer.child_type)) { - elem_result_loc->value->special = ConstValSpecialRuntime; - } - ir_analyze_store_ptr(ira, elem_result_loc->scope, elem_result_loc->source_node, elem_result_loc, deref, true); - } - } - - const_ptrs.deinit(); - - return ir_get_deref(ira, scope, source_node, new_struct_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_array_cat(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Stage1AirInst *op1 = instruction->op1->child; - ZigType *op1_type = op1->value->type; - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - ZigType *op2_type = op2->value->type; - if (type_is_invalid(op2_type)) - return ira->codegen->invalid_inst_gen; - - if (is_tuple(op1_type) && is_tuple(op2_type)) { - return ir_analyze_tuple_cat(ira, instruction->base.scope, instruction->base.source_node, op1, op2); - } - - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (!op1_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); - if (!op2_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *sentinel1 = nullptr; - ZigValue *op1_array_val; - size_t op1_array_index; - size_t op1_array_end; - ZigType *child_type; - if (op1_type->id == ZigTypeIdArray) { - child_type = op1_type->data.array.child_type; - op1_array_val = op1_val; - op1_array_index = 0; - op1_array_end = op1_type->data.array.len; - sentinel1 = op1_type->data.array.sentinel; - } else if (op1_type->id == ZigTypeIdPointer && - op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op1_type->data.pointer.sentinel != nullptr && - op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray) - { - child_type = op1_type->data.pointer.child_type; - op1_array_val = op1_val->data.x_ptr.data.base_array.array_val; - op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index; - op1_array_end = op1_array_val->type->data.array.len; - sentinel1 = op1_type->data.pointer.sentinel; - } else if (is_slice(op1_type)) { - ZigType *ptr_type = op1_type->data.structure.fields[slice_ptr_index]->type_entry; - child_type = ptr_type->data.pointer.child_type; - ZigValue *ptr_val = op1_val->data.x_struct.fields[slice_ptr_index]; - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; - op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - ZigValue *len_val = op1_val->data.x_struct.fields[slice_len_index]; - op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint); - sentinel1 = ptr_type->data.pointer.sentinel; - } else if (op1_type->id == ZigTypeIdPointer && - op1_type->data.pointer.ptr_len == PtrLenSingle && - op1_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *array_type = op1_type->data.pointer.child_type; - child_type = array_type->data.array.child_type; - op1_array_val = const_ptr_pointee(ira, ira->codegen, op1_val, op1->source_node); - if (op1_array_val == nullptr) - return ira->codegen->invalid_inst_gen; - op1_array_index = 0; - op1_array_end = array_type->data.array.len; - sentinel1 = array_type->data.array.sentinel; - } else { - ir_add_error(ira, op1, buf_sprintf("expected array, found '%s'", buf_ptr(&op1->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel2 = nullptr; - ZigValue *op2_array_val; - size_t op2_array_index; - size_t op2_array_end; - bool op2_type_valid; - if (op2_type->id == ZigTypeIdArray) { - op2_type_valid = op2_type->data.array.child_type == child_type; - op2_array_val = op2_val; - op2_array_index = 0; - op2_array_end = op2_array_val->type->data.array.len; - sentinel2 = op2_type->data.array.sentinel; - } else if (op2_type->id == ZigTypeIdPointer && - op2_type->data.pointer.sentinel != nullptr && - op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray) - { - op2_type_valid = op2_type->data.pointer.child_type == child_type; - op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; - op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; - op2_array_end = op2_array_val->type->data.array.len; - - sentinel2 = op2_type->data.pointer.sentinel; - } else if (is_slice(op2_type)) { - ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index]->type_entry; - op2_type_valid = ptr_type->data.pointer.child_type == child_type; - ZigValue *ptr_val = op2_val->data.x_struct.fields[slice_ptr_index]; - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; - op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - ZigValue *len_val = op2_val->data.x_struct.fields[slice_len_index]; - op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint); - - sentinel2 = ptr_type->data.pointer.sentinel; - } else if (op2_type->id == ZigTypeIdPointer && op2_type->data.pointer.ptr_len == PtrLenSingle && - op2_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *array_type = op2_type->data.pointer.child_type; - op2_type_valid = array_type->data.array.child_type == child_type; - op2_array_val = const_ptr_pointee(ira, ira->codegen, op2_val, op2->source_node); - if (op2_array_val == nullptr) - return ira->codegen->invalid_inst_gen; - op2_array_index = 0; - op2_array_end = array_type->data.array.len; - - sentinel2 = array_type->data.array.sentinel; - } else { - ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (!op2_type_valid) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel; - if (sentinel1 != nullptr && sentinel2 != nullptr) { - // When there is a sentinel mismatch, no sentinel on the result. The type system - // will catch this if it is a problem. - sentinel = const_values_equal(ira->codegen, sentinel1, sentinel2) ? sentinel1 : nullptr; - } else if (sentinel1 != nullptr) { - sentinel = sentinel1; - } else if (sentinel2 != nullptr) { - sentinel = sentinel2; - } else { - sentinel = nullptr; - } - - // The type of result is populated in the following if blocks - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - ZigValue *out_val = result->value; - - ZigValue *out_array_val; - size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index); - if (op1_type->id == ZigTypeIdPointer || op2_type->id == ZigTypeIdPointer) { - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = out_array_val; - out_val->type = get_pointer_to_type(ira->codegen, out_array_val->type, true); - } else if (is_slice(op1_type) || is_slice(op2_type)) { - ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, child_type, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, sentinel); - result->value->type = get_slice_type(ira->codegen, ptr_type); - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - - out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - - out_val->data.x_struct.fields[slice_ptr_index]->type = ptr_type; - out_val->data.x_struct.fields[slice_ptr_index]->special = ConstValSpecialStatic; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.data.base_array.array_val = out_array_val; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.data.base_array.elem_index = 0; - - out_val->data.x_struct.fields[slice_len_index]->type = ira->codegen->builtin_types.entry_usize; - out_val->data.x_struct.fields[slice_len_index]->special = ConstValSpecialStatic; - bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index]->data.x_bigint, new_len); - } else if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) { - result->value->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - out_array_val = out_val; - } else { - result->value->type = get_pointer_to_type_extra2(ira->codegen, child_type, true, false, PtrLenUnknown, - 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel); - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = out_array_val; - out_val->data.x_ptr.data.base_array.elem_index = 0; - } - - if (op1_array_val->data.x_array.special == ConstArraySpecialUndef && - op2_array_val->data.x_array.special == ConstArraySpecialUndef) - { - out_array_val->data.x_array.special = ConstArraySpecialUndef; - return result; - } - - uint64_t full_len = new_len + ((sentinel != nullptr) ? 1 : 0); - out_array_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(full_len); - // TODO handle the buf case here for an optimization - expand_undef_array(ira->codegen, op1_array_val); - expand_undef_array(ira->codegen, op2_array_val); - - size_t next_index = 0; - for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, &op1_array_val->data.x_array.data.s_none.elements[i]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - } - for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, &op2_array_val->data.x_array.data.s_none.elements[i]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - } - if (next_index < full_len) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, sentinel); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - next_index += 1; - } - assert(next_index == full_len); - - return result; -} - -static Stage1AirInst *ir_analyze_tuple_mult(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2) -{ - Error err; - ZigType *op1_type = op1->value->type; - uint64_t op1_field_count = op1_type->data.structure.src_field_count; - - uint64_t mult_amt; - if (!ir_resolve_usize(ira, op2, &mult_amt)) - return ira->codegen->invalid_inst_gen; - - uint64_t new_field_count; - if (mul_u64_overflow(op1_field_count, mult_amt, &new_field_count)) { - ir_add_error_node(ira, source_node, buf_sprintf("operation results in overflow")); - return ira->codegen->invalid_inst_gen; - } - - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - scope, source_node, bare_name, nullptr); - ZigType *new_type = get_partial_container_type(ira->codegen, scope, - ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto); - new_type->data.structure.special = StructSpecialInferredTuple; - new_type->data.structure.resolve_status = ResolveStatusBeingInferred; - new_type->data.structure.src_field_count = new_field_count; - new_type->data.structure.fields = realloc_type_struct_fields( - new_type->data.structure.fields, 0, new_field_count); - - Stage1AirInst *new_struct_ptr = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - new_type, nullptr, false, true); - - for (uint64_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field = op1_type->data.structure.fields[i % op1_field_count]; - TypeStructField *new_field = new_type->data.structure.fields[i]; - - new_field->name = buf_sprintf("%" ZIG_PRI_u64, i); - new_field->type_entry = src_field->type_entry; - new_field->type_val = src_field->type_val; - new_field->src_index = i; - new_field->decl_node = src_field->decl_node; - new_field->init_val = src_field->init_val; - new_field->is_comptime = src_field->is_comptime; - } - - if ((err = type_resolve(ira->codegen, new_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigList const_ptrs = {}; - for (uint64_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field = op1_type->data.structure.fields[i % op1_field_count]; - TypeStructField *dst_field = new_type->data.structure.fields[i]; - - Stage1AirInst *field_value = ir_analyze_struct_value_field_value( - ira, scope, source_node, op1, src_field); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *dest_ptr = ir_analyze_struct_field_ptr( - ira, scope, source_node, dst_field, new_struct_ptr, new_type, true); - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(field_value)) { - const_ptrs.append(dest_ptr); - } - - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr( - ira, scope, source_node, dest_ptr, field_value, true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (const_ptrs.length != new_field_count) { - new_struct_ptr->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - if (!type_requires_comptime(ira->codegen, elem_result_loc->value->type->data.pointer.child_type)) { - elem_result_loc->value->special = ConstValSpecialRuntime; - } - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, deref, true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - } - - const_ptrs.deinit(); - - return ir_get_deref(ira, scope, source_node, new_struct_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_array_mult(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - bool want_ptr_to_array = false; - ZigType *array_type; - ZigValue *array_val; - if (op1->value->type->id == ZigTypeIdArray) { - array_type = op1->value->type; - array_val = ir_resolve_const(ira, op1, UndefOk); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - } else if (op1->value->type->id == ZigTypeIdPointer && - op1->value->type->data.pointer.ptr_len == PtrLenSingle && - op1->value->type->data.pointer.child_type->id == ZigTypeIdArray) - { - array_type = op1->value->type->data.pointer.child_type; - Stage1AirInst *array_inst = ir_get_deref(ira, op1->scope, op1->source_node, op1, nullptr); - if (type_is_invalid(array_inst->value->type)) - return ira->codegen->invalid_inst_gen; - array_val = ir_resolve_const(ira, array_inst, UndefOk); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - want_ptr_to_array = true; - } else if (is_tuple(op1->value->type)) { - return ir_analyze_tuple_mult(ira, instruction->base.scope, instruction->base.source_node, op1, op2); - } else { - ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint64_t mult_amt; - if (!ir_resolve_usize(ira, op2, &mult_amt)) - return ira->codegen->invalid_inst_gen; - - uint64_t old_array_len = array_type->data.array.len; - uint64_t new_array_len; - - if (mul_u64_overflow(old_array_len, mult_amt, &new_array_len)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("operation results in overflow")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = array_type->data.array.child_type; - ZigType *result_array_type = get_array_type(ira->codegen, child_type, new_array_len, - array_type->data.array.sentinel); - - Stage1AirInst *array_result; - if (array_val->special == ConstValSpecialUndef || array_val->data.x_array.special == ConstArraySpecialUndef) { - array_result = ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, result_array_type); - } else { - array_result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_array_type); - ZigValue *out_val = array_result->value; - - switch (type_has_one_possible_value(ira->codegen, result_array_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - goto skip_computation; - case OnePossibleValueNo: - break; - } - - // TODO optimize the buf case - expand_undef_array(ira->codegen, array_val); - size_t extra_null_term = (array_type->data.array.sentinel != nullptr) ? 1 : 0; - out_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(new_array_len + extra_null_term); - - uint64_t i = 0; - for (uint64_t x = 0; x < mult_amt; x += 1) { - for (uint64_t y = 0; y < old_array_len; y += 1) { - ZigValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(ira->codegen, elem_dest_val, &array_val->data.x_array.data.s_none.elements[y]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_val; - elem_dest_val->parent.data.p_array.elem_index = i; - i += 1; - } - } - assert(i == new_array_len); - - if (array_type->data.array.sentinel != nullptr) { - ZigValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(ira->codegen, elem_dest_val, array_type->data.array.sentinel); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_val; - elem_dest_val->parent.data.p_array.elem_index = i; - i += 1; - } - } -skip_computation: - if (want_ptr_to_array) { - return ir_get_ref(ira, instruction->base.scope, instruction->base.source_node, array_result, true, false); - } else { - return array_result; - } -} - -static Stage1AirInst *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, - Stage1ZirInstMergeErrSets *instruction) -{ - ZigType *op1_type = ir_resolve_error_set_type(ira, instruction->base.source_node, instruction->op1->child); - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *op2_type = ir_resolve_error_set_type(ira, instruction->base.source_node, instruction->op2->child); - if (type_is_invalid(op2_type)) - return ira->codegen->invalid_inst_gen; - - if (!resolve_inferred_error_set(ira->codegen, op1_type, instruction->op1->child->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (!resolve_inferred_error_set(ira->codegen, op2_type, instruction->op2->child->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (type_is_global_error_set(op1_type) || - type_is_global_error_set(op2_type)) - { - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_global_error_set); - } - - size_t errors_count = ira->codegen->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) { - ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name); - heap::c_allocator.deallocate(errors, errors_count); - - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, result_type); -} - - -static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - IrBinOp op_id = bin_op_instruction->op_id; - switch (op_id) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - return ir_analyze_bin_op_bool(ira, bin_op_instruction); - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - return ir_analyze_bin_op_cmp(ira, bin_op_instruction); - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpShlSat: - return ir_analyze_bit_shift(ira, bin_op_instruction); - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpAdd: - case IrBinOpAddWrap: - case IrBinOpSub: - case IrBinOpSubWrap: - case IrBinOpMult: - case IrBinOpMultWrap: - case IrBinOpDivUnspecified: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - case IrBinOpDivExact: - case IrBinOpRemUnspecified: - case IrBinOpRemRem: - case IrBinOpRemMod: - case IrBinOpMax: - case IrBinOpMin: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - return ir_analyze_bin_op_math(ira, bin_op_instruction); - case IrBinOpArrayCat: - return ir_analyze_array_cat(ira, bin_op_instruction); - case IrBinOpArrayMult: - return ir_analyze_array_mult(ira, bin_op_instruction); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_decl_var(IrAnalyze *ira, Stage1ZirInstDeclVar *decl_var_instruction) { - Error err; - ZigVar *var = decl_var_instruction->var; - - ZigType *explicit_type = nullptr; - Stage1AirInst *var_type = nullptr; - if (decl_var_instruction->var_type != nullptr) { - var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type); - explicit_type = validate_var_type(ira->codegen, &var->decl_node->data.variable_declaration, proposed_type); - if (type_is_invalid(explicit_type)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - } - - AstNode *source_node = decl_var_instruction->base.source_node; - - bool is_comptime_var = ir_get_var_is_comptime(var); - - bool var_class_requires_const = false; - - Stage1AirInst *var_ptr = decl_var_instruction->ptr->child; - // if this is null, a compiler error happened and did not initialize the variable. - // if there are no compile errors there may be a missing ir_expr_wrap in pass1 IR generation. - if (var_ptr == nullptr || type_is_invalid(var_ptr->value->type)) { - src_assert(var_ptr != nullptr || ira->codegen->errors.length != 0, - decl_var_instruction->base.source_node); - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - - // The ir_build_var_decl_src call is supposed to pass a pointer to the allocation, not an initialization value. - src_assert(var_ptr->value->type->id == ZigTypeIdPointer, decl_var_instruction->base.source_node); - - ZigType *result_type = var_ptr->value->type->data.pointer.child_type; - if (type_is_invalid(result_type)) { - result_type = ira->codegen->builtin_types.entry_invalid; - } else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) { - zig_unreachable(); - } - - ZigValue *init_val = nullptr; - if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.source_node); - if (init_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (is_comptime_var) { - if (var->gen_is_const) { - var->const_value = init_val; - } else { - var->const_value = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, var->const_value, init_val); - } - } - } - - switch (type_requires_comptime(ira->codegen, result_type)) { - case ReqCompTimeInvalid: - result_type = ira->codegen->builtin_types.entry_invalid; - break; - case ReqCompTimeYes: - var_class_requires_const = true; - if (!var->gen_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' must be const or comptime", - buf_ptr(&result_type->name))); - if(result_type->id == ZigTypeIdComptimeInt || result_type -> id == ZigTypeIdComptimeFloat) { - add_error_note(ira->codegen, msg, source_node, buf_sprintf("to modify this variable at runtime, it must be given an explicit fixed-size number type")); - } - result_type = ira->codegen->builtin_types.entry_invalid; - } - break; - case ReqCompTimeNo: - if (init_val != nullptr && value_is_comptime(init_val)) { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - decl_var_instruction->base.source_node, init_val, UndefOk))) - { - result_type = ira->codegen->builtin_types.entry_invalid; - } else if (init_val->type->id == ZigTypeIdFn && - init_val->special != ConstValSpecialUndef && - init_val->data.x_ptr.special == ConstPtrSpecialFunction && - init_val->data.x_ptr.data.fn.fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) - { - var_class_requires_const = true; - if (!var->src_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("functions marked inline must be stored in const or comptime var")); - AstNode *proto_node = init_val->data.x_ptr.data.fn.fn_entry->proto_node; - add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); - result_type = ira->codegen->builtin_types.entry_invalid; - } - } - } - break; - } - - while (var->next_var != nullptr) { - var = var->next_var; - } - - // This must be done after possibly creating a new variable above - var->ref_count = 0; - - var->ptr_instruction = var_ptr; - var->var_type = result_type; - assert(var->var_type); - - if (type_is_invalid(result_type)) { - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - - if (decl_var_instruction->align_value == nullptr) { - if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - var->align_bytes = get_ptr_align(ira->codegen, var_ptr->value->type); - } else { - if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, nullptr, &var->align_bytes)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - } - } - - if (init_val != nullptr && value_is_comptime(init_val)) { - // Resolve ConstPtrMutInfer - if (var->gen_is_const) { - var_ptr->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else if (is_comptime_var) { - var_ptr->value->data.x_ptr.mut = ConstPtrMutComptimeVar; - } else { - // we need a runtime ptr but we have a comptime val. - // since it's a comptime val there are no instructions for it. - // we memcpy the init value here - Stage1AirInst *deref = ir_get_deref(ira, var_ptr->scope, var_ptr->source_node, var_ptr, nullptr); - if (type_is_invalid(deref->value->type)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - // If this assertion trips, something is wrong with the IR instructions, because - // we expected the above deref to return a constant value, but it created a runtime - // instruction. - assert(deref->value->special != ConstValSpecialRuntime); - var_ptr->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, var_ptr->scope, var_ptr->source_node, var_ptr, deref, false); - } - if (instr_is_comptime(var_ptr) && (is_comptime_var || (var_class_requires_const && var->gen_is_const))) { - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - } else if (is_comptime_var) { - ir_add_error_node(ira, decl_var_instruction->base.source_node, - buf_sprintf("cannot store runtime value in compile time variable")); - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - - ZigFn *fn_entry = ira->fn; - if (fn_entry) - fn_entry->variable_list.append(var); - - return ir_build_var_decl_gen(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node, var, var_ptr); -} - -static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirInstExport *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *options = instruction->options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = options->value->type; - assert(options_type->id == ZigTypeIdStruct); - - TypeStructField *name_field = find_struct_type_field(options_type, buf_create_from_str("name")); - src_assert(name_field != nullptr, instruction->base.source_node); - Stage1AirInst *name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, name_field); - if (type_is_invalid(name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *linkage_field = find_struct_type_field(options_type, buf_create_from_str("linkage")); - src_assert(linkage_field != nullptr, instruction->base.source_node); - Stage1AirInst *linkage_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, linkage_field); - if (type_is_invalid(linkage_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *section_field = find_struct_type_field(options_type, buf_create_from_str("section")); - src_assert(section_field != nullptr, instruction->base.source_node); - Stage1AirInst *section_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, section_field); - if (type_is_invalid(section_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // The `section` field is optional, we have to unwrap it first - Stage1AirInst *non_null_check = ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, section_inst); - bool is_non_null; - if (!ir_resolve_bool(ira, non_null_check, &is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *section_str_inst = nullptr; - if (is_non_null) { - section_str_inst = ir_analyze_optional_value_payload_value(ira, instruction->base.scope, instruction->base.source_node, section_inst, false); - if (type_is_invalid(section_str_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - // Resolve all the comptime values - Buf *symbol_name = ir_resolve_str(ira, name_inst); - if (!symbol_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(symbol_name) < 1) { - ir_add_error(ira, name_inst, - buf_sprintf("exported symbol name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - GlobalLinkageId global_linkage_id; - if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) - return ira->codegen->invalid_inst_gen; - - Buf *section_name = nullptr; - if (section_str_inst != nullptr && !(section_name = ir_resolve_str(ira, section_str_inst))) - return ira->codegen->invalid_inst_gen; - - // TODO: This function needs to be audited. - // It's not clear how all the different types are supposed to be handled. - // Need comprehensive tests for exporting one thing in one file and declaring an extern var - // in another file. - TldFn *tld_fn = heap::c_allocator.create(); - tld_fn->base.id = TldIdFn; - tld_fn->base.source_node = instruction->base.source_node; - - auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, &tld_fn->base); - if (entry) { - AstNode *other_export_node = entry->value->source_node; - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); - add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol here")); - return ira->codegen->invalid_inst_gen; - } - - Error err; - bool want_var_export = false; - switch (target->value->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - case ZigTypeIdFn: { - assert(target->value->data.x_ptr.special == ConstPtrSpecialFunction); - ZigFn *fn_entry = target->value->data.x_ptr.data.fn.fn_entry; - tld_fn->fn_entry = fn_entry; - CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; - switch (cc) { - case CallingConventionUnspecified: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function must specify calling convention")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionAsync: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function cannot be async")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionInline: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function cannot be inline")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); - fn_entry->section_name = section_name; - break; - } - } break; - case ZigTypeIdStruct: - if (is_slice(target->value->type)) { - ir_add_error(ira, target, - buf_sprintf("unable to export value of type '%s'", buf_ptr(&target->value->type->name))); - } else if (target->value->type->data.structure.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported struct value must be declared extern")); - add_error_note(ira->codegen, msg, target->value->type->data.structure.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdUnion: - if (target->value->type->data.unionation.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported union value must be declared extern")); - add_error_note(ira->codegen, msg, target->value->type->data.unionation.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdEnum: - if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - if (!target->value->type->data.enumeration.has_explicit_tag_type) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported enum value without explicit integer tag type")); - add_error_note(ira->codegen, msg, target->value->type->data.enumeration.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdArray: { - bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, ExternPositionOther, &ok_type))) - return ira->codegen->invalid_inst_gen; - - if (!ok_type) { - ir_add_error(ira, target, - buf_sprintf("array element type '%s' not extern-compatible", - buf_ptr(&target->value->type->data.array.child_type->name))); - } else { - want_var_export = true; - } - break; - } - case ZigTypeIdMetaType: { - ZigType *type_value = target->value->data.x_type; - switch (type_value->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - if (is_slice(type_value)) { - ir_add_error(ira, target, - buf_sprintf("unable to export type '%s'", buf_ptr(&type_value->name))); - } else if (type_value->data.structure.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported struct must be declared extern")); - add_error_note(ira->codegen, msg, type_value->data.structure.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdUnion: - if (type_value->data.unionation.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported union must be declared extern")); - add_error_note(ira->codegen, msg, type_value->data.unionation.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdEnum: - if ((err = type_resolve(ira->codegen, type_value, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - if (!type_value->data.enumeration.has_explicit_tag_type) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported enum without explicit integer tag type")); - add_error_note(ira->codegen, msg, type_value->data.enumeration.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdFn: { - if (type_value->data.fn.fn_type_id.cc == CallingConventionUnspecified) { - ir_add_error(ira, target, - buf_sprintf("exported function type must specify calling convention")); - } - } break; - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdBool: - case ZigTypeIdVector: - break; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error(ira, target, - buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); - break; - } - } break; - case ZigTypeIdInt: - want_var_export = true; - break; - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdVector: - zig_panic("TODO export const value of type %s", buf_ptr(&target->value->type->name)); - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdEnumLiteral: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error(ira, target, - buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value->type->name))); - break; - } - - // TODO audit the various ways to use @export - if (want_var_export && target->id == Stage1AirInstIdLoadPtr) { - Stage1AirInstLoadPtr *load_ptr = reinterpret_cast(target); - if (load_ptr->ptr->id == Stage1AirInstIdVarPtr) { - Stage1AirInstVarPtr *var_ptr = reinterpret_cast(load_ptr->ptr); - ZigVar *var = var_ptr->var; - add_var_export(ira->codegen, var, buf_ptr(symbol_name), global_linkage_id); - var->section_name = section_name; - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node); - -static Stage1AirInst *ir_analyze_instruction_extern(IrAnalyze *ira, Stage1ZirInstExtern *instruction) { - Stage1AirInst *type_inst = instruction->type->child; - if (type_is_invalid(type_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *options = instruction->options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = options->value->type; - assert(options_type->id == ZigTypeIdStruct); - - TypeStructField *name_field = find_struct_type_field(options_type, buf_create_from_str("name")); - src_assert(name_field != nullptr, instruction->base.source_node); - Stage1AirInst *name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, name_field); - if (type_is_invalid(name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *linkage_field = find_struct_type_field(options_type, buf_create_from_str("linkage")); - src_assert(linkage_field != nullptr, instruction->base.source_node); - Stage1AirInst *linkage_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, linkage_field); - if (type_is_invalid(linkage_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *is_thread_local_field = find_struct_type_field(options_type, buf_create_from_str("is_thread_local")); - src_assert(is_thread_local_field != nullptr, instruction->base.source_node); - Stage1AirInst *is_thread_local_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, is_thread_local_field); - if (type_is_invalid(is_thread_local_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *library_name_field = find_struct_type_field(options_type, buf_create_from_str("library_name")); - src_assert(library_name_field != nullptr, instruction->base.source_node); - Stage1AirInst *library_name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, library_name_field); - if (type_is_invalid(library_name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // The `library_name` field is optional, we have to unwrap it first - Stage1AirInst *non_null_check = ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, library_name_inst); - bool is_non_null; - if (!ir_resolve_bool(ira, non_null_check, &is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *library_name_val_inst = nullptr; - if (is_non_null) { - library_name_val_inst = ir_analyze_optional_value_payload_value(ira, instruction->base.scope, instruction->base.source_node, library_name_inst, false); - if (type_is_invalid(library_name_val_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - // Resolve all the comptime values - ZigType *value_type = ir_resolve_type(ira, type_inst); - if (type_is_invalid(value_type)) - return ira->codegen->invalid_inst_gen; - - if (get_src_ptr_type(value_type) == nullptr) { - ir_add_error(ira, name_inst, - buf_sprintf("expected (optional) pointer type or function")); - return ira->codegen->invalid_inst_gen; - } - - Buf *symbol_name = ir_resolve_str(ira, name_inst); - if (!symbol_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(symbol_name) == 0) { - ir_add_error(ira, name_inst, - buf_sprintf("extern symbol name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - Buf *library_name = nullptr; - if (library_name_val_inst) { - library_name = ir_resolve_str(ira, library_name_val_inst); - if (!library_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(library_name) == 0) { - ir_add_error(ira, library_name_inst, - buf_sprintf("library name name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - add_link_lib_symbol(ira, library_name, symbol_name, instruction->base.source_node); - - buf_destroy(library_name); - } - - GlobalLinkageId global_linkage_id; - if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) - return ira->codegen->invalid_inst_gen; - - bool is_thread_local; - if (!ir_resolve_bool(ira, is_thread_local_inst, &is_thread_local)) - return ira->codegen->invalid_inst_gen; - - ZigType *expr_type = value_type; - if (global_linkage_id == GlobalLinkageIdWeak && value_type->id != ZigTypeIdOptional) - expr_type = get_optional_type(ira->codegen, expr_type); - - // Create a bogus Tld object to keep track of the extern symbol. - // XXX: Find a better way to do this (in stage2). - TldFn *tld_fn = heap::c_allocator.create(); - tld_fn->base.id = TldIdFn; - tld_fn->base.source_node = instruction->base.source_node; - - auto entry = ira->codegen->external_symbol_names.put_unique(symbol_name, &tld_fn->base); - if (entry) { - AstNode *other_extern_node = entry->value->source_node; - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("extern symbol collision: '%s'", buf_ptr(symbol_name))); - add_error_note(ira->codegen, msg, other_extern_node, buf_sprintf("other symbol here")); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_extern_gen(ira, instruction->base.scope, instruction->base.source_node, symbol_name, global_linkage_id, - is_thread_local, expr_type); -} - -static bool ira_has_err_ret_trace(IrAnalyze *ira) { - ZigFn *fn = ira->fn; - return fn != nullptr && fn->calls_or_awaits_errorable_fn && ira->codegen->have_err_ret_tracing; -} - -static Stage1AirInst *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, - Stage1ZirInstErrorReturnTrace *instruction) -{ - ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false); - if (instruction->optional == IrInstErrorReturnTraceNull) { - ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type); - if (!ira_has_err_ret_trace(ira)) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, optional_type); - ZigValue *out_val = result->value; - assert(get_src_ptr_type(optional_type) != nullptr); - out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - out_val->data.x_ptr.data.hard_coded_addr.addr = 0; - return result; - } - return ir_build_error_return_trace_gen(ira, instruction->base.scope, - instruction->base.source_node, instruction->optional, optional_type); - } else { - assert(ira->codegen->have_err_ret_tracing); - return ir_build_error_return_trace_gen(ira, instruction->base.scope, - instruction->base.source_node, instruction->optional, ptr_to_stack_trace_type); - } -} - -static Stage1AirInst *ir_analyze_instruction_error_union(IrAnalyze *ira, Stage1ZirInstErrorUnion *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueErrUnionType *lazy_err_union_type = heap::c_allocator.create(); - lazy_err_union_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_err_union_type->base; - lazy_err_union_type->base.id = LazyValueIdErrUnionType; - - lazy_err_union_type->err_set_type = instruction->err_set->child; - if (ir_resolve_type_lazy(ira, lazy_err_union_type->err_set_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_err_union_type->payload_type = instruction->payload->child; - if (ir_resolve_type_lazy(ira, lazy_err_union_type->payload_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_alloca(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *var_type, - uint32_t align, const char *name_hint, bool force_comptime) -{ - Error err; - - ZigValue *pointee = ira->codegen->pass1_arena->create(); - pointee->special = ConstValSpecialUndef; - pointee->llvm_align = align; - - Stage1AirInstAlloca *result = ir_build_alloca_gen(ira, scope, source_node, align, name_hint); - result->base.value->special = ConstValSpecialStatic; - result->base.value->data.x_ptr.special = ConstPtrSpecialRef; - result->base.value->data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer; - result->base.value->data.x_ptr.data.ref.pointee = pointee; - - bool var_type_has_bits; - if ((err = type_has_bits2(ira->codegen, var_type, &var_type_has_bits))) - return ira->codegen->invalid_inst_gen; - if (align != 0) { - if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (!var_type_has_bits) { - ir_add_error_node(ira, source_node, - buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned", - name_hint, buf_ptr(&var_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - assert(result->base.value->data.x_ptr.special != ConstPtrSpecialInvalid); - - pointee->type = var_type; - result->base.value->type = get_pointer_to_type_extra(ira->codegen, var_type, false, false, - PtrLenSingle, align, 0, 0, false); - - if (!force_comptime) { - ZigFn *fn_entry = ira->fn; - if (fn_entry != nullptr) { - fn_entry->alloca_gen_list.append(result); - } - } - return &result->base; -} - -static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: - case ResultLocIdVar: - case ResultLocIdBitCast: - case ResultLocIdCast: - return nullptr; - case ResultLocIdInstruction: - return result_loc->source_instruction->child->value->type; - case ResultLocIdReturn: - return ira->explicit_return_type; - case ResultLocIdPeer: - return reinterpret_cast(result_loc)->parent->resolved_type; - } - zig_unreachable(); -} - -static bool type_can_bit_cast(ZigType *t) { - switch (t->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - return false; - default: - // TODO list these types out explicitly, there are probably some other invalid ones here - return true; - } -} - -static void set_up_result_loc_for_inferred_comptime(IrAnalyze *ira, Stage1AirInst *ptr) { - ZigValue *undef_child = ira->codegen->pass1_arena->create(); - undef_child->type = ptr->value->type->data.pointer.child_type; - undef_child->special = ConstValSpecialUndef; - ptr->value->special = ConstValSpecialStatic; - ptr->value->data.x_ptr.mut = ConstPtrMutInfer; - ptr->value->data.x_ptr.special = ConstPtrSpecialRef; - ptr->value->data.x_ptr.data.ref.pointee = undef_child; -} - -static Error ir_result_has_type(IrAnalyze *ira, ResultLoc *result_loc, bool *out) { - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: - case ResultLocIdPeer: - *out = false; - return ErrorNone; - case ResultLocIdReturn: - case ResultLocIdInstruction: - case ResultLocIdBitCast: - *out = true; - return ErrorNone; - case ResultLocIdCast: { - ResultLocCast *result_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ErrorSemanticAnalyzeFail; - *out = (dest_type != ira->codegen->builtin_types.entry_anytype); - return ErrorNone; - } - case ResultLocIdVar: - *out = reinterpret_cast(result_loc)->var->decl_node->data.variable_declaration.type != nullptr; - return ErrorNone; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_resolve_no_result_loc(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type) -{ - if (type_is_invalid(value_type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInstAlloca *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, 0, ""); - alloca_gen->base.value->type = get_pointer_to_type_extra(ira->codegen, value_type, false, false, - PtrLenSingle, 0, 0, 0, false); - set_up_result_loc_for_inferred_comptime(ira, &alloca_gen->base); - ZigFn *fn_entry = ira->fn; - if (fn_entry != nullptr && get_scope_typeof(suspend_source_instr->scope) == nullptr) { - fn_entry->alloca_gen_list.append(alloca_gen); - } - result_loc->written = true; - result_loc->resolved_loc = &alloca_gen->base; - return result_loc->resolved_loc; -} - -static bool result_loc_is_discard(ResultLoc *result_loc_pass1) { - if (result_loc_pass1->id == ResultLocIdInstruction && - result_loc_pass1->source_instruction->id == Stage1ZirInstIdConst) - { - Stage1ZirInstConst *const_inst = reinterpret_cast(result_loc_pass1->source_instruction); - if (value_is_comptime(const_inst->value) && - const_inst->value->type->id == ZigTypeIdPointer && - const_inst->value->data.x_ptr.special == ConstPtrSpecialDiscard) - { - return true; - } - } - return false; -} - -// when calling this function, at the callsite must check for result type noreturn and propagate it up -static Stage1AirInst *ir_resolve_result_raw(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, - bool allow_discard) -{ - Error err; - if (result_loc->resolved_loc != nullptr) { - // allow to redo the result location if the value is known and comptime and the previous one isn't - if (value == nullptr || !instr_is_comptime(value) || instr_is_comptime(result_loc->resolved_loc)) { - return result_loc->resolved_loc; - } - } - result_loc->gen_instruction = value; - result_loc->implicit_elem_type = value_type; - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: { - if (value != nullptr) { - return nullptr; - } - // need to return a result location and don't have one. use a stack allocation - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - case ResultLocIdVar: { - ResultLocVar *result_loc_var = reinterpret_cast(result_loc); - assert(result_loc->source_instruction->id == Stage1ZirInstIdAlloca); - Stage1ZirInstAlloca *alloca_src = reinterpret_cast(result_loc->source_instruction); - - ZigVar *var = result_loc_var->var; - if (var->var_type != nullptr && !ir_get_var_is_comptime(var)) { - // This is at least the second time we've seen this variable declaration during analysis. - // This means that this is actually a different variable due to, e.g. an inline while loop. - // We make a new variable so that it can hold a different type, and so the debug info can - // be distinct. - ZigVar *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, - buf_create_from_str(var->name), var->src_is_const, var->gen_is_const, - var->shadowable, var->is_comptime, true); - new_var->align_bytes = var->align_bytes; - - var->next_var = new_var; - var = new_var; - } - if (value_type->id == ZigTypeIdUnreachable || value_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("variable of type '%s' not allowed", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - if (alloca_src->base.child == nullptr || var->ptr_instruction == nullptr) { - bool force_comptime; - if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) - return ira->codegen->invalid_inst_gen; - uint32_t align = 0; - if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, nullptr, &align)) { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *alloca_gen = ir_analyze_alloca(ira, - result_loc->source_instruction->scope, - result_loc->source_instruction->source_node, value_type, - align, alloca_src->name_hint, force_comptime); - if (force_runtime) { - alloca_gen->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - alloca_gen->value->special = ConstValSpecialRuntime; - } - if (alloca_src->base.child != nullptr && !result_loc->written) { - alloca_src->base.child->ref_count = 0; - } - alloca_src->base.child = alloca_gen; - var->ptr_instruction = alloca_gen; - } - result_loc->written = true; - result_loc->resolved_loc = alloca_src->base.child; - return alloca_src->base.child; - } - case ResultLocIdInstruction: { - result_loc->written = true; - result_loc->resolved_loc = result_loc->source_instruction->child; - return result_loc->resolved_loc; - } - case ResultLocIdReturn: { - if (value != nullptr) { - reinterpret_cast(result_loc)->implicit_return_type_done = true; - ira->src_implicit_return_type_list.append(value); - } - result_loc->written = true; - result_loc->resolved_loc = ira->return_ptr; - return result_loc->resolved_loc; - } - case ResultLocIdPeer: { - ResultLocPeer *result_peer = reinterpret_cast(result_loc); - ResultLocPeerParent *peer_parent = result_peer->parent; - - if (peer_parent->peers.length == 1) { - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime, true); - result_peer->suspend_pos.basic_block_index = SIZE_MAX; - result_peer->suspend_pos.instruction_index = SIZE_MAX; - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - - bool is_condition_comptime; - if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_condition_comptime)) - return ira->codegen->invalid_inst_gen; - if (is_condition_comptime) { - peer_parent->skipped = true; - return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime, true); - } - bool peer_parent_has_type; - if ((err = ir_result_has_type(ira, peer_parent->parent, &peer_parent_has_type))) - return ira->codegen->invalid_inst_gen; - if (peer_parent_has_type) { - peer_parent->skipped = true; - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime || !is_condition_comptime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - peer_parent->parent->written = true; - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - - if (peer_parent->resolved_type == nullptr) { - if (peer_parent->end_bb->suspend_instruction_ref == nullptr) { - peer_parent->end_bb->suspend_instruction_ref = suspend_source_instr; - } - Stage1AirInst *unreach_inst = ira_suspend(ira, suspend_source_instr, result_peer->next_bb, - &result_peer->suspend_pos); - if (result_peer->next_bb == nullptr) { - ir_start_next_bb(ira); - } - return unreach_inst; - } - - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - peer_parent->resolved_type, nullptr, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - // because is_condition_comptime is false, we mark this a runtime pointer - parent_result_loc->value->special = ConstValSpecialRuntime; - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - case ResultLocIdCast: { - ResultLocCast *result_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type == ira->codegen->builtin_types.entry_anytype) { - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - - Stage1AirInst *casted_value; - if (value != nullptr) { - casted_value = ir_implicit_cast2(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, value, dest_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - dest_type = casted_value->value->type; - } else { - casted_value = nullptr; - } - - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_cast->parent, - dest_type, casted_value, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - - ZigType *parent_ptr_type = parent_result_loc->value->type; - assert(parent_ptr_type->id == ZigTypeIdPointer); - - if ((err = type_resolve(ira->codegen, parent_ptr_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - uint64_t parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); - if ((err = type_resolve(ira->codegen, value_type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen; - } - if (!type_has_bits(ira->codegen, value_type)) { - parent_ptr_align = 0; - } - // If we're casting from a sentinel-terminated array to a non-sentinel-terminated array, - // we actually need the result location pointer to *not* have a sentinel. Otherwise the generated - // memcpy will write an extra byte to the destination, and THAT'S NO GOOD. - ZigType *ptr_elem_type; - if (value_type->id == ZigTypeIdArray && value_type->data.array.sentinel != nullptr && - dest_type->id == ZigTypeIdArray && dest_type->data.array.sentinel == nullptr) - { - ptr_elem_type = get_array_type(ira->codegen, value_type->data.array.child_type, - value_type->data.array.len, nullptr); - } else { - ptr_elem_type = value_type; - } - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ptr_elem_type, - parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, - parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); - - ConstCastOnly const_cast_result = types_match_const_cast_only(ira, - parent_result_loc->value->type, ptr_type, - result_cast->base.source_instruction->source_node, false); - if (const_cast_result.id == ConstCastResultIdInvalid) - return ira->codegen->invalid_inst_gen; - if (const_cast_result.id != ConstCastResultIdOk) { - if (allow_discard) { - return parent_result_loc; - } - // We will not be able to provide a result location for this value. Create - // a new result location. - result_cast->parent->written = false; - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - - result_loc->written = true; - result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, parent_result_loc, - parent_result_loc->source_node, ptr_type, - result_cast->base.source_instruction->source_node, false, false); - return result_loc->resolved_loc; - } - case ResultLocIdBitCast: { - ResultLocBitCast *result_bit_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_cg_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, dest_type, &dest_cg_ptr_type))) - return ira->codegen->invalid_inst_gen; - if (dest_cg_ptr_type != nullptr) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (!type_can_bit_cast(dest_type)) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *value_cg_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, value_type, &value_cg_ptr_type))) - return ira->codegen->invalid_inst_gen; - if (value_cg_ptr_type != nullptr) { - ir_add_error_node(ira, suspend_source_instr->source_node, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (!type_can_bit_cast(value_type)) { - ir_add_error_node(ira, suspend_source_instr->source_node, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *bitcasted_value; - if (value != nullptr) { - bitcasted_value = ir_analyze_bit_cast(ira, result_loc->source_instruction->scope, - result_loc->source_instruction->source_node, value, dest_type); - dest_type = bitcasted_value->value->type; - } else { - bitcasted_value = nullptr; - } - - if (bitcasted_value != nullptr && type_is_invalid(bitcasted_value->value->type)) { - return bitcasted_value; - } - - bool parent_was_written = result_bit_cast->parent->written; - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, bitcasted_value, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - ZigType *parent_ptr_type = parent_result_loc->value->type; - assert(parent_ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = parent_ptr_type->data.pointer.child_type; - - if (result_loc_is_discard(result_bit_cast->parent)) { - assert(allow_discard); - return parent_result_loc; - } - - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, value_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if (child_type != ira->codegen->builtin_types.entry_anytype) { - if (type_size(ira->codegen, child_type) != type_size(ira->codegen, value_type)) { - // pointer cast won't work; we need a temporary location. - result_bit_cast->parent->written = parent_was_written; - result_loc->written = true; - result_loc->resolved_loc = ir_resolve_result(ira, suspend_source_instr, no_result_loc(), - value_type, bitcasted_value, force_runtime, true); - return result_loc->resolved_loc; - } - } - uint64_t parent_ptr_align = 0; - if (type_has_bits(ira->codegen, value_type)) parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type, - parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, - parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); - - result_loc->written = true; - result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, parent_result_loc, - parent_result_loc->source_node, ptr_type, - result_bit_cast->base.source_instruction->source_node, false, false); - return result_loc->resolved_loc; - } - } - zig_unreachable(); -} - -static Stage1AirInst *ir_resolve_result(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc_pass1, ZigType *value_type, Stage1AirInst *value, bool force_runtime, - bool allow_discard) -{ - if (!allow_discard && result_loc_is_discard(result_loc_pass1)) { - result_loc_pass1 = no_result_loc(); - } - bool was_written = result_loc_pass1->written; - Stage1AirInst *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type, - value, force_runtime, allow_discard); - if (result_loc == nullptr || result_loc->value->type->id == ZigTypeIdUnreachable || - type_is_invalid(result_loc->value->type)) - { - return result_loc; - } - - if ((force_runtime || (value != nullptr && !instr_is_comptime(value))) && - result_loc_pass1->written && result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) - { - result_loc->value->special = ConstValSpecialRuntime; - } - - InferredStructField *isf = result_loc->value->type->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field; - Stage1AirInst *casted_ptr; - if (isf->already_resolved) { - field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - casted_ptr = result_loc; - } else { - isf->already_resolved = true; - // Now it's time to add the field to the struct type. - uint32_t old_field_count = isf->inferred_struct_type->data.structure.src_field_count; - uint32_t new_field_count = old_field_count + 1; - isf->inferred_struct_type->data.structure.src_field_count = new_field_count; - isf->inferred_struct_type->data.structure.fields = realloc_type_struct_fields( - isf->inferred_struct_type->data.structure.fields, old_field_count, new_field_count); - - field = isf->inferred_struct_type->data.structure.fields[old_field_count]; - field->name = isf->field_name; - field->type_entry = value_type; - field->type_val = create_const_type(ira->codegen, field->type_entry); - field->src_index = old_field_count; - field->decl_node = value ? value->source_node : suspend_source_instr->source_node; - if (value && instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefOk); - if (!val) - return ira->codegen->invalid_inst_gen; - field->is_comptime = true; - field->init_val = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, field->init_val, val); - return result_loc; - } - - ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false); - if (instr_is_comptime(result_loc)) { - casted_ptr = ir_const(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, struct_ptr_type); - copy_const_val(ira->codegen, casted_ptr->value, result_loc->value); - casted_ptr->value->type = struct_ptr_type; - } else { - casted_ptr = result_loc; - } - if (instr_is_comptime(casted_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, - suspend_source_instr->source_node); - struct_val->special = ConstValSpecialStatic; - struct_val->data.x_struct.fields = realloc_const_vals_ptrs(ira->codegen, - struct_val->data.x_struct.fields, old_field_count, new_field_count); - - ZigValue *field_val = struct_val->data.x_struct.fields[old_field_count]; - field_val->special = ConstValSpecialUndef; - field_val->type = field->type_entry; - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = struct_val; - field_val->parent.data.p_struct.field_index = old_field_count; - } - } - } - - result_loc = ir_analyze_struct_field_ptr(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, field, casted_ptr, - isf->inferred_struct_type, true); - if (type_is_invalid(result_loc->value->type)) { - return result_loc; - } - result_loc_pass1->resolved_loc = result_loc; - } - - if (was_written) { - return result_loc; - } - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, suspend_source_instr->source_node); - ZigType *actual_elem_type = result_loc->value->type->data.pointer.child_type; - if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && - value_type->id != ZigTypeIdNull && value_type->id != ZigTypeIdUndefined) - { - bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, actual_elem_type, value_type); - if (!same_comptime_repr) { - result_loc_pass1->written = was_written; - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, result_loc, false, true); - } - } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion && - value_type->id != ZigTypeIdUndefined) - { - if (value_type->id == ZigTypeIdErrorSet) { - return ir_analyze_unwrap_err_code(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, result_loc, true); - } else { - Stage1AirInst *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, - suspend_source_instr->scope, suspend_source_instr->source_node, - result_loc, false, true); - ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; - if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && - value_type->id != ZigTypeIdNull && value_type->id != ZigTypeIdUndefined) - { - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, unwrapped_err_ptr, false, true); - } else { - return unwrapped_err_ptr; - } - } - } - return result_loc; -} - -static Stage1AirInst *ir_analyze_instruction_resolve_result(IrAnalyze *ira, Stage1ZirInstResolveResult *instruction) { - ZigType *implicit_elem_type; - if (instruction->ty == nullptr) { - if (instruction->result_loc->id == ResultLocIdCast) { - implicit_elem_type = ir_resolve_type(ira, - instruction->result_loc->source_instruction->child); - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } else if (instruction->result_loc->id == ResultLocIdReturn) { - implicit_elem_type = ira->explicit_return_type; - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } else { - implicit_elem_type = ira->codegen->builtin_types.entry_anytype; - } - if (implicit_elem_type == ira->codegen->builtin_types.entry_anytype) { - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - instruction->base.scope, instruction->base.source_node, bare_name, nullptr); - - StructSpecial struct_special = StructSpecialInferredStruct; - if (instruction->base.source_node->type == NodeTypeContainerInitExpr && - instruction->base.source_node->data.container_init_expr.kind == ContainerInitKindArray) - { - struct_special = StructSpecialInferredTuple; - } - - ZigType *inferred_struct_type = get_partial_container_type(ira->codegen, - instruction->base.scope, ContainerKindStruct, instruction->base.source_node, - buf_ptr(name), bare_name, ContainerLayoutAuto); - inferred_struct_type->data.structure.special = struct_special; - inferred_struct_type->data.structure.resolve_status = ResolveStatusBeingInferred; - implicit_elem_type = inferred_struct_type; - } - } else { - implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - implicit_elem_type, nullptr, false, true); - if (result_loc != nullptr) - return result_loc; - - ZigFn *fn = ira->fn; - if (fn != nullptr && fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync && - instruction->result_loc->id == ResultLocIdReturn) - { - result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(), - implicit_elem_type, nullptr, false, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - result_loc->value->special = ConstValSpecialRuntime; - return result_loc; - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, implicit_elem_type); - result->value->special = ConstValSpecialUndef; - Stage1AirInst *ptr = ir_get_ref(ira, instruction->base.scope, instruction->base.source_node, result, false, false); - ptr->value->data.x_ptr.mut = ConstPtrMutComptimeVar; - return ptr; -} - -static void ir_reset_result(ResultLoc *result_loc) { - result_loc->written = false; - result_loc->resolved_loc = nullptr; - result_loc->gen_instruction = nullptr; - result_loc->implicit_elem_type = nullptr; - switch (result_loc->id) { - case ResultLocIdInvalid: - zig_unreachable(); - case ResultLocIdPeerParent: { - ResultLocPeerParent *peer_parent = reinterpret_cast(result_loc); - peer_parent->skipped = false; - peer_parent->done_resuming = false; - peer_parent->resolved_type = nullptr; - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ir_reset_result(&peer_parent->peers.at(i)->base); - } - break; - } - case ResultLocIdVar: { - Stage1ZirInstAlloca *alloca_src = reinterpret_cast(result_loc->source_instruction); - alloca_src->base.child = nullptr; - break; - } - case ResultLocIdReturn: - reinterpret_cast(result_loc)->implicit_return_type_done = false; - break; - case ResultLocIdPeer: - case ResultLocIdNone: - case ResultLocIdInstruction: - case ResultLocIdBitCast: - case ResultLocIdCast: - break; - } -} - -static Stage1AirInst *ir_analyze_instruction_reset_result(IrAnalyze *ira, Stage1ZirInstResetResult *instruction) { - ir_reset_result(instruction->result_loc); - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *get_async_call_result_loc(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *fn_ret_type, bool is_async_call_builtin, Stage1AirInst **args_ptr, size_t args_len, - Stage1AirInst *ret_ptr_uncasted) -{ - src_assert(is_async_call_builtin, source_node); - if (type_is_invalid(ret_ptr_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - if (ret_ptr_uncasted->value->type->id == ZigTypeIdVoid) { - // Result location will be inside the async frame. - return nullptr; - } - return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false)); -} - -static Stage1AirInst *ir_analyze_async_call(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigFn *fn_entry, - ZigType *fn_type, Stage1AirInst *fn_ref, Stage1AirInst **casted_args, size_t arg_count, - Stage1AirInst *casted_new_stack, bool is_async_call_builtin, Stage1AirInst *ret_ptr_uncasted, - ResultLoc *call_result_loc) -{ - if (fn_entry == nullptr) { - if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { - ir_add_error(ira, fn_ref, - buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - if (casted_new_stack == nullptr) { - ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); - return ira->codegen->invalid_inst_gen; - } - } - if (casted_new_stack != nullptr) { - ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type; - Stage1AirInst *ret_ptr = get_async_call_result_loc(ira, scope, source_node, fn_ret_type, is_async_call_builtin, - casted_args, arg_count, ret_ptr_uncasted); - if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); - - Stage1AirInstCall *call_gen = ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, - arg_count, casted_args, CallModifierAsync, casted_new_stack, - is_async_call_builtin, ret_ptr, anyframe_type); - return &call_gen->base; - } else { - ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); - Stage1AirInst *result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - frame_type, nullptr, true, false); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - result_loc = ir_implicit_cast2(ira, scope, source_node, result_loc, - get_pointer_to_type(ira->codegen, frame_type, false)); - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - return &ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, arg_count, - casted_args, CallModifierAsync, casted_new_stack, - is_async_call_builtin, result_loc, frame_type)->base; - } -} -static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, - Stage1AirInst *arg, Scope **exec_scope, size_t *next_proto_i) -{ - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - - Stage1AirInst *casted_arg; - if (param_decl_node->data.param_decl.anytype_token == 0) { - AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = ir_analyze_type_expr(ira, *exec_scope, param_type_node); - if (type_is_invalid(param_type)) - return false; - - casted_arg = ir_implicit_cast(ira, arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return false; - } else { - casted_arg = arg; - } - - ZigValue *arg_val = ir_resolve_const(ira, casted_arg, UndefOk); - if (!arg_val) - return false; - - Buf *param_name = param_decl_node->data.param_decl.name; - ZigVar *var = add_variable(ira->codegen, param_decl_node, - *exec_scope, param_name, true, arg_val, nullptr, arg_val->type); - *exec_scope = var->child_scope; - *next_proto_i += 1; - - return true; -} - -static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_node, - Stage1AirInst *arg, AstNode *arg_src, Scope **child_scope, size_t *next_proto_i, - GenericFnTypeId *generic_id, FnTypeId *fn_type_id, Stage1AirInst **casted_args, - ZigFn *impl_fn) -{ - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - bool is_var_args = param_decl_node->data.param_decl.is_var_args; - bool arg_part_of_generic_id = false; - Stage1AirInst *casted_arg; - - ZigType *param_info_type = nullptr; - if (is_var_args) { - arg_part_of_generic_id = true; - casted_arg = arg; - param_info_type = arg->value->type; - } else { - if (param_decl_node->data.param_decl.anytype_token == 0) { - AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = ir_analyze_type_expr(ira, *child_scope, param_type_node); - if (type_is_invalid(param_type)) - return false; - - casted_arg = ir_implicit_cast2(ira, arg->scope, arg_src, arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return false; - - param_info_type = param_type; - } else { - arg_part_of_generic_id = true; - casted_arg = arg; - param_info_type = arg->value->type; - } - } - - bool comptime_arg = param_decl_node->data.param_decl.is_comptime; - if (!comptime_arg) { - switch (type_requires_comptime(ira->codegen, casted_arg->value->type)) { - case ReqCompTimeInvalid: - return false; - case ReqCompTimeYes: - comptime_arg = true; - break; - case ReqCompTimeNo: - break; - } - } - - ZigValue *arg_val; - - if (comptime_arg && !instr_is_comptime(casted_arg)) { - ir_add_error(ira, casted_arg, - buf_sprintf("runtime value cannot be passed to comptime arg")); - return false; - } - if (comptime_arg) { - arg_part_of_generic_id = true; - arg_val = ir_resolve_const(ira, casted_arg, UndefBad); - if (!arg_val) - return false; - } else { - arg_val = create_const_runtime(ira->codegen, casted_arg->value->type); - } - if (arg_part_of_generic_id) { - copy_const_val(ira->codegen, &generic_id->params[generic_id->param_count], arg_val); - generic_id->param_count += 1; - } - - Buf *param_name = param_decl_node->data.param_decl.name; - if (!param_name) return false; - if (!is_var_args) { - ZigVar *var = add_variable(ira->codegen, param_decl_node, - *child_scope, param_name, true, arg_val, nullptr, arg_val->type); - *child_scope = var->child_scope; - var->shadowable = !comptime_arg; - - *next_proto_i += 1; - } else if (casted_arg->value->type->id == ZigTypeIdComptimeInt || - casted_arg->value->type->id == ZigTypeIdComptimeFloat) - { - ir_add_error(ira, casted_arg, - buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557")); - return false; - } - - if (!comptime_arg) { - casted_args[fn_type_id->param_count] = casted_arg; - FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; - param_info->type = param_info_type; - param_info->is_noalias = param_decl_node->data.param_decl.is_noalias; - impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; - fn_type_id->param_count += 1; - } - - return true; -} - -static Stage1AirInst *ir_get_var_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var) { - while (var->next_var != nullptr) { - var = var->next_var; - } - - if (var->var_type == nullptr || type_is_invalid(var->var_type)) - return ira->codegen->invalid_inst_gen; - - bool is_volatile = false; - ZigType *var_ptr_type = get_pointer_to_type_extra(ira->codegen, var->var_type, - var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); - - if (var->ptr_instruction != nullptr) { - return ir_implicit_cast(ira, var->ptr_instruction, var_ptr_type); - } - - bool comptime_var_mem = ir_get_var_is_comptime(var); - bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; - - Stage1AirInst *result = ir_build_var_ptr_gen(ira, scope, source_node, var); - result->value->type = var_ptr_type; - - if (!linkage_makes_it_runtime && !var->is_thread_local && value_is_comptime(var->const_value)) { - ZigValue *val = var->const_value; - switch (val->special) { - case ConstValSpecialRuntime: - break; - case ConstValSpecialStatic: // fallthrough - case ConstValSpecialLazy: // fallthrough - case ConstValSpecialUndef: { - ConstPtrMut ptr_mut; - if (comptime_var_mem) { - ptr_mut = ConstPtrMutComptimeVar; - } else if (var->gen_is_const) { - ptr_mut = ConstPtrMutComptimeConst; - } else { - assert(!comptime_var_mem); - ptr_mut = ConstPtrMutRuntimeVar; - } - result->value->special = ConstValSpecialStatic; - result->value->data.x_ptr.mut = ptr_mut; - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = val; - return result; - } - } - } - - bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); - result->value->data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; - - return result; -} - -// This function is called when a comptime value becomes accessible at runtime. -static void mark_comptime_value_escape(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigValue *val) { - src_assert(value_is_comptime(val), source_node); - if (val->special == ConstValSpecialUndef) - return; - - if (val->type->id == ZigTypeIdFn && val->type->data.fn.fn_type_id.cc == CallingConventionUnspecified) { - src_assert(val->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - if (val->data.x_ptr.data.fn.fn_entry->non_async_node == nullptr) { - val->data.x_ptr.data.fn.fn_entry->non_async_node = source_node; - } - } -} - -static Stage1AirInst *ir_analyze_store_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *uncasted_value, bool allow_write_through_const) -{ - assert(ptr->value->type->id == ZigTypeIdPointer); - - if (ptr->value->data.x_ptr.special == ConstPtrSpecialDiscard) { - if (uncasted_value->value->type->id == ZigTypeIdErrorUnion || - uncasted_value->value->type->id == ZigTypeIdErrorSet) - { - ir_add_error_node(ira, source_node, buf_sprintf("error is discarded. consider using `try`, `catch`, or `if`")); - return ira->codegen->invalid_inst_gen; - } - return ir_const_void(ira, scope, source_node); - } - - if (ptr->value->type->data.pointer.is_const && !allow_write_through_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = ptr->value->type->data.pointer.child_type; - Stage1AirInst *value = ir_implicit_cast(ira, uncasted_value, child_type); - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, scope, source_node); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(ptr) && ptr->value->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if (!allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - if ((allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) || - ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar || - ptr->value->data.x_ptr.mut == ConstPtrMutInfer) - { - if (instr_is_comptime(value)) { - ZigValue *dest_val = const_ptr_pointee(ira, ira->codegen, ptr->value, source_node); - if (dest_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (dest_val->special != ConstValSpecialRuntime) { - copy_const_val(ira->codegen, dest_val, value->value); - - if (ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar && - ira->new_irb.current_basic_block->must_be_comptime_source_node == nullptr) - { - ira->new_irb.current_basic_block->must_be_comptime_source_node = source_node; - } - return ir_const_void(ira, scope, source_node); - } - } - if (ptr->value->data.x_ptr.mut == ConstPtrMutInfer) { - ptr->value->special = ConstValSpecialRuntime; - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("cannot store runtime value in compile time variable")); - ZigValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; - - return ira->codegen->invalid_inst_gen; - } - } - } - - if (ptr->value->type->data.pointer.inferred_struct_field != nullptr && - child_type == ira->codegen->builtin_types.entry_anytype) - { - child_type = ptr->value->type->data.pointer.inferred_struct_field->inferred_struct_type; - } - - switch (type_requires_comptime(ira->codegen, child_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeYes: - switch (type_has_one_possible_value(ira->codegen, ptr->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - ir_add_error_node(ira, source_node, - buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, scope, source_node); - } - zig_unreachable(); - case ReqCompTimeNo: - break; - } - - if (instr_is_comptime(value)) { - mark_comptime_value_escape(ira, scope, source_node, value->value); - } - - // If this is a store to a pointer with a runtime-known vector index, - // we have to figure out the Stage1AirInst which represents the index and - // emit a Stage1AirInstVectorStoreElem, or emit a compile error - // explaining why it is impossible for this store to work. Which is that - // the pointer address is of the vector; without the element index being known - // we cannot properly perform the insertion. - if (ptr->value->type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - if (ptr->id == Stage1AirInstIdElemPtr) { - Stage1AirInstElemPtr *elem_ptr = (Stage1AirInstElemPtr *)ptr; - return ir_build_vector_store_elem(ira, scope, source_node, elem_ptr->array_ptr, - elem_ptr->elem_index, value); - } - ir_add_error(ira, ptr, - buf_sprintf("unable to determine vector element index of type '%s'", - buf_ptr(&ptr->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_store_ptr_gen(ira, scope, source_node, ptr, value); -} - -static Stage1AirInst *analyze_casted_new_stack(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *new_stack, AstNode *new_stack_src, bool is_async_call_builtin, ZigFn *fn_entry) -{ - if (new_stack == nullptr) - return nullptr; - - if (!is_async_call_builtin && - arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr) - { - ir_add_error_node(ira, source_node, - buf_sprintf("target arch '%s' does not support calling with a new stack", - target_arch_name(ira->codegen->zig_target->arch))); - } - - if (is_async_call_builtin && - fn_entry != nullptr && new_stack->value->type->id == ZigTypeIdPointer && - new_stack->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, - get_fn_frame_type(ira->codegen, fn_entry), false); - return ir_implicit_cast(ira, new_stack, needed_frame_type); - } else { - // XXX The stack alignment is hardcoded to 16 here and in - // std.Target.stack_align. - const uint32_t required_align = is_async_call_builtin ? - get_async_frame_align_bytes(ira->codegen) : 16; - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, required_align, 0, 0, false); - ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); - ira->codegen->need_frame_size_prefix_data = true; - return ir_implicit_cast2(ira, new_stack->scope, new_stack_src, new_stack, u8_slice); - } -} - -static Stage1AirInst *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, ZigType *fn_type, Stage1AirInst *fn_ref, - Stage1AirInst *first_arg_ptr, AstNode *first_arg_ptr_src, CallModifier modifier, - Stage1AirInst *new_stack, AstNode *new_stack_src, bool is_async_call_builtin, - Stage1AirInst **args_ptr, size_t args_len, Stage1AirInst *ret_ptr, ResultLoc *call_result_loc) -{ - Error err; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; - - // for extern functions, the var args argument is not counted. - // for zig functions, it is. - size_t var_args_1_or_0; - if (fn_type_id->cc == CallingConventionC) { - var_args_1_or_0 = 0; - } else { - var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0; - } - size_t src_param_count = fn_type_id->param_count - var_args_1_or_0; - size_t call_param_count = args_len + first_arg_1_or_0; - - AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;; - - if (fn_type_id->cc == CallingConventionNaked) { - ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("unable to call function with naked calling convention")); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (fn_type_id->is_var_args) { - if (call_param_count < src_param_count) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected at least %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize "", - src_param_count, call_param_count)); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - } else if (src_param_count != call_param_count) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize "", - src_param_count, call_param_count)); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (modifier == CallModifierCompileTime) { - // If we are evaluating an extern function in a TypeOf call, we can return an undefined value - // of its return type. - if (fn_entry != nullptr && get_scope_typeof(scope) != nullptr && - fn_proto_node->data.fn_proto.is_extern) { - - assert(fn_entry->body_node == nullptr); - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *return_type = ir_analyze_type_expr(ira, scope, return_type_node); - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - - return ir_const_undef(ira, scope, source_node, return_type); - } - - // No special handling is needed for compile time evaluation of generic functions. - if (!fn_entry || fn_entry->body_node == nullptr) { - ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - if (!ir_emit_backward_branch(ira, source_node)) - return ira->codegen->invalid_inst_gen; - - // Fork a scope of the function with known values for the parameters. - Scope *exec_scope = &fn_entry->fndef_scope->base; - - size_t next_proto_i = 0; - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - bool first_arg_known_bare = false; - if (fn_type_id->next_param_index >= 1) { - ZigType *param_type = fn_type_id->param_info[next_proto_i].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - first_arg_known_bare = param_type->id != ZigTypeIdPointer; - } - - Stage1AirInst *first_arg; - if (!first_arg_known_bare) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_proto_i)) - return ira->codegen->invalid_inst_gen; - } - - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *old_arg = args_ptr[call_i]; - - if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i)) - return ira->codegen->invalid_inst_gen; - } - - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - if (return_type_node == nullptr) { - ir_add_error(ira, fn_ref, - buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); - return ira->codegen->invalid_inst_gen; - } - ZigType *specified_return_type = ir_analyze_type_expr(ira, exec_scope, return_type_node); - if (type_is_invalid(specified_return_type)) - return ira->codegen->invalid_inst_gen; - ZigType *return_type; - ZigType *inferred_err_set_type = nullptr; - if (fn_proto_node->data.fn_proto.auto_err_set) { - inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry); - if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); - } else { - return_type = specified_return_type; - } - - bool cacheable = fn_eval_cacheable(exec_scope, return_type); - ZigValue *result = nullptr; - if (cacheable) { - // We are about to put ZigValues into a hash map. The hash of a lazy value and a - // fully resolved value must equal, and so we must resolve the lazy values here. - // The hash function asserts that none of the values are lazy. - { - Scope *scope = exec_scope; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if ((err = ir_resolve_lazy_recurse( - var_scope->var->decl_node, - var_scope->var->const_value))) - { - return ira->codegen->invalid_inst_gen; - } - } else if (scope->id == ScopeIdFnDef) { - break; - } else { - zig_unreachable(); - } - scope = scope->parent; - } - } - - auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); - if (entry) - result = entry->value; - } - - if (result == nullptr) { - // Analyze the fn body block like any other constant expression. - AstNode *body_node = fn_entry->body_node; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, return_type, &result, &result_ptr); - - if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - fn_entry, nullptr, source_node, nullptr, ira->new_irb.exec, return_type_node, - UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - - if (inferred_err_set_type != nullptr) { - inferred_err_set_type->data.error_set.incomplete = false; - if (result->type->id == ZigTypeIdErrorUnion) { - ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; - if (err != nullptr) { - inferred_err_set_type->data.error_set.err_count = 1; - inferred_err_set_type->data.error_set.errors = heap::c_allocator.create(); - inferred_err_set_type->data.error_set.errors[0] = err; - } - ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type; - inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; - } else if (result->type->id == ZigTypeIdErrorSet) { - inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors; - } - } - - if (cacheable) { - ira->codegen->memoized_fn_eval_table.put(exec_scope, result); - } - - if (type_is_invalid(result->type)) { - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *new_instruction = ir_const_move(ira, scope, source_node, result); - return ir_finish_anal(ira, new_instruction); - } - - if (fn_type->data.fn.is_generic) { - if (!fn_entry) { - ir_add_error(ira, fn_ref, - buf_sprintf("calling a generic function requires compile-time known function value")); - return ira->codegen->invalid_inst_gen; - } - - size_t new_fn_arg_count = first_arg_1_or_0 + args_len; - - Stage1AirInst **casted_args = heap::c_allocator.allocate(new_fn_arg_count); - - // Fork a scope of the function with known values for the parameters. - Scope *parent_scope = fn_entry->fndef_scope->base.parent; - ZigFn *impl_fn = create_fn(ira->codegen, fn_proto_node); - impl_fn->param_source_nodes = heap::c_allocator.allocate(new_fn_arg_count); - buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); - impl_fn->fndef_scope = create_fndef_scope(ira->codegen, impl_fn->body_node, parent_scope, impl_fn); - impl_fn->child_scope = &impl_fn->fndef_scope->base; - FnTypeId inst_fn_type_id = {0}; - init_fn_type_id(&inst_fn_type_id, fn_proto_node, fn_type_id->cc, new_fn_arg_count); - inst_fn_type_id.param_count = 0; - inst_fn_type_id.is_var_args = false; - - // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly - // as the key in generic_table - GenericFnTypeId *generic_id = heap::c_allocator.create(); - generic_id->fn_entry = fn_entry; - generic_id->param_count = 0; - generic_id->params = ira->codegen->pass1_arena->allocate(new_fn_arg_count); - size_t next_proto_i = 0; - - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - bool first_arg_known_bare = false; - if (fn_type_id->next_param_index >= 1) { - ZigType *param_type = fn_type_id->param_info[next_proto_i].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - first_arg_known_bare = param_type->id != ZigTypeIdPointer; - } - - Stage1AirInst *first_arg; - if (!first_arg_known_bare) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, - first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, first_arg, first_arg_ptr_src, - &impl_fn->child_scope, &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn)) - { - return ira->codegen->invalid_inst_gen; - } - } - - ZigFn *parent_fn_entry = ira->fn; - assert(parent_fn_entry); - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *arg = args_ptr[call_i]; - - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - - if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, arg->source_node, - &impl_fn->child_scope, - &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn)) - { - return ira->codegen->invalid_inst_gen; - } - } - - if (fn_proto_node->data.fn_proto.align_expr != nullptr) { - ZigValue *align_result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, get_align_amt_type(ira->codegen), &align_result, &result_ptr); - if ((err = ir_eval_const_value(ira->codegen, impl_fn->child_scope, - fn_proto_node->data.fn_proto.align_expr, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, - nullptr, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInstConst *const_instruction = ir_create_inst_noval(&ira->new_irb, - impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); - const_instruction->base.value = align_result; - - uint32_t align_bytes = 0; - ir_resolve_align(ira, &const_instruction->base, nullptr, &align_bytes); - impl_fn->align_bytes = align_bytes; - inst_fn_type_id.alignment = align_bytes; - } - - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node); - if (type_is_invalid(specified_return_type)) - return ira->codegen->invalid_inst_gen; - - if(!is_valid_return_type(specified_return_type)){ - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name))); - add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here")); - - Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name); - if (tld != nullptr) { - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (fn_proto_node->data.fn_proto.auto_err_set) { - ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn); - if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); - } else { - inst_fn_type_id.return_type = specified_return_type; - } - - switch (type_requires_comptime(ira->codegen, specified_return_type)) { - case ReqCompTimeYes: - // Throw out our work and call the function as if it were comptime. - return ir_analyze_fn_call(ira, scope, source_node, fn_entry, fn_type, fn_ref, first_arg_ptr, - first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin, - args_ptr, args_len, ret_ptr, call_result_loc); - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - // We are about to put ZigValues into a hash map. The hash of a lazy value and a - // fully resolved value must equal, and so we must resolve the lazy values here. - // The hash function asserts that none of the values are lazy. - for (size_t i = 0; i < generic_id->param_count; i += 1) { - ZigValue *generic_param = &generic_id->params[i]; - if (generic_param->special != ConstValSpecialRuntime) { - if ((err = ir_resolve_lazy_recurse(source_node, generic_param))) { - return ira->codegen->invalid_inst_gen; - } - } - } - - auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn); - if (existing_entry) { - // throw away all our work and use the existing function - impl_fn = existing_entry->value; - } else { - // finish instantiating the function - impl_fn->type_entry = get_fn_type(ira->codegen, &inst_fn_type_id); - if (type_is_invalid(impl_fn->type_entry)) - return ira->codegen->invalid_inst_gen; - - impl_fn->analyzed_executable.source_node = source_node; - impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; - impl_fn->branch_quota = *ira->backward_branch_quota; - - ira->codegen->fn_defs.append(impl_fn); - } - - FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; - - if (fn_type_can_fail(impl_fn_type_id)) { - parent_fn_entry->calls_or_awaits_errorable_fn = true; - } - - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, new_stack, - new_stack_src, is_async_call_builtin, impl_fn); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - size_t impl_param_count = impl_fn_type_id->param_count; - if (modifier == CallModifierAsync) { - Stage1AirInst *result = ir_analyze_async_call(ira, scope, source_node, impl_fn, impl_fn->type_entry, - nullptr, casted_args, impl_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, - call_result_loc); - return ir_finish_anal(ira, result); - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, impl_fn_type_id->return_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - impl_fn_type_id->return_type, nullptr, true, false); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, impl_fn_type_id->return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, scope, source_node, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; - if (res_child_type == ira->codegen->builtin_types.entry_anytype) { - res_child_type = impl_fn_type_id->return_type; - } - if (!handle_is_ptr(ira->codegen, res_child_type)) { - ir_reset_result(call_result_loc); - result_loc = nullptr; - } - } - } else if (is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, scope, source_node, impl_fn_type_id->return_type, - is_async_call_builtin, args_ptr, args_len, ret_ptr); - if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result_loc = nullptr; - } - - if (impl_fn_type_id->cc == CallingConventionAsync && - parent_fn_entry->inferred_async_node == nullptr && - modifier != CallModifierNoSuspend) - { - parent_fn_entry->inferred_async_node = fn_ref->source_node; - parent_fn_entry->inferred_async_fn = impl_fn; - } - - Stage1AirInstCall *new_call_instruction = ir_build_call_gen(ira, scope, source_node, - impl_fn, nullptr, impl_param_count, casted_args, modifier, casted_new_stack, - is_async_call_builtin, result_loc, impl_fn_type_id->return_type); - - if (get_scope_typeof(scope) == nullptr) { - parent_fn_entry->call_list.append(new_call_instruction); - } - - return ir_finish_anal(ira, &new_call_instruction->base); - } - - ZigFn *parent_fn_entry = ira->fn; - assert(fn_type_id->return_type != nullptr); - assert(parent_fn_entry != nullptr); - if (fn_type_can_fail(fn_type_id)) { - parent_fn_entry->calls_or_awaits_errorable_fn = true; - } - - - Stage1AirInst **casted_args = heap::c_allocator.allocate(call_param_count); - size_t next_arg_index = 0; - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - ZigType *param_type = fn_type_id->param_info[next_arg_index].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *first_arg; - if (param_type->id == ZigTypeIdPointer) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, - first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_arg = ir_implicit_cast2(ira, first_arg->scope, first_arg_ptr_src, first_arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_args[next_arg_index] = casted_arg; - next_arg_index += 1; - } - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *old_arg = args_ptr[call_i]; - if (type_is_invalid(old_arg->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_arg; - if (next_arg_index < src_param_count) { - ZigType *param_type = fn_type_id->param_info[next_arg_index].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - casted_arg = ir_implicit_cast(ira, old_arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - casted_arg = old_arg; - } - - casted_args[next_arg_index] = casted_arg; - next_arg_index += 1; - } - - assert(next_arg_index == call_param_count); - - ZigType *return_type = fn_type_id->return_type; - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - - if (fn_entry != nullptr && fn_type_id->cc == CallingConventionInline && modifier == CallModifierNeverInline) { - ir_add_error_node(ira, source_node, - buf_sprintf("no-inline call of inline function")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, new_stack, new_stack_src, - is_async_call_builtin, fn_entry); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - if (modifier == CallModifierAsync) { - Stage1AirInst *result = ir_analyze_async_call(ira, scope, source_node, fn_entry, fn_type, fn_ref, - casted_args, call_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, call_result_loc); - return ir_finish_anal(ira, result); - } - - if (fn_type_id->cc == CallingConventionAsync && - parent_fn_entry->inferred_async_node == nullptr && - modifier != CallModifierNoSuspend) - { - parent_fn_entry->inferred_async_node = fn_ref->source_node; - parent_fn_entry->inferred_async_fn = fn_entry; - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, return_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - return_type, nullptr, true, false); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *expected_return_type = result_loc->value->type->data.pointer.child_type; - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, scope, source_node, - dummy_value, expected_return_type); - if (type_is_invalid(dummy_result->value->type)) { - if ((return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) && - expected_return_type->id != ZigTypeIdErrorUnion && expected_return_type->id != ZigTypeIdErrorSet) - { - if (call_result_loc->id == ResultLocIdReturn) { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, - ira->explicit_return_type_source_node, buf_sprintf("function cannot return an error")); - } else { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, result_loc->source_node, - buf_sprintf("cannot store an error in type '%s'", buf_ptr(&expected_return_type->name))); - } - } - return ira->codegen->invalid_inst_gen; - } - if (expected_return_type == ira->codegen->builtin_types.entry_anytype) { - expected_return_type = return_type; - } - if (!handle_is_ptr(ira->codegen, expected_return_type)) { - ir_reset_result(call_result_loc); - result_loc = nullptr; - } - } - } else if (is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, scope, source_node, return_type, is_async_call_builtin, - args_ptr, args_len, ret_ptr); - if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result_loc = nullptr; - } - - Stage1AirInstCall *new_call_instruction = ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, - call_param_count, casted_args, modifier, casted_new_stack, - is_async_call_builtin, result_loc, return_type); - if (get_scope_typeof(scope) == nullptr) { - parent_fn_entry->call_list.append(new_call_instruction); - } - return ir_finish_anal(ira, &new_call_instruction->base); -} - -static Stage1AirInst *ir_analyze_fn_call_src(IrAnalyze *ira, Stage1ZirInstCall *call_instruction, - ZigFn *fn_entry, ZigType *fn_type, Stage1AirInst *fn_ref, - Stage1AirInst *first_arg_ptr, AstNode *first_arg_ptr_src, CallModifier modifier) -{ - Stage1AirInst *new_stack = nullptr; - AstNode *new_stack_src = nullptr; - if (call_instruction->new_stack) { - new_stack = call_instruction->new_stack->child; - if (type_is_invalid(new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - new_stack_src = call_instruction->new_stack->source_node; - } - Stage1AirInst **args_ptr = heap::c_allocator.allocate(call_instruction->arg_count); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - args_ptr[i] = call_instruction->args[i]->child; - if (type_is_invalid(args_ptr[i]->value->type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *ret_ptr = nullptr; - if (call_instruction->ret_ptr != nullptr) { - ret_ptr = call_instruction->ret_ptr->child; - if (type_is_invalid(ret_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_analyze_fn_call(ira, call_instruction->base.scope, - call_instruction->base.source_node, fn_entry, fn_type, fn_ref, - first_arg_ptr, first_arg_ptr_src, modifier, new_stack, new_stack_src, - call_instruction->is_async_call_builtin, args_ptr, call_instruction->arg_count, ret_ptr, - call_instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, call_instruction->arg_count); - return result; -} - -static Stage1AirInst *ir_analyze_call_extra(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1ZirInst *pass1_options, Stage1ZirInst *pass1_fn_ref, Stage1AirInst **args_ptr, size_t args_len, - ResultLoc *result_loc) -{ - Stage1AirInst *options = pass1_options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *fn_ref = pass1_fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier")); - src_assert(modifier_field != nullptr, source_node); - Stage1AirInst *modifier_inst = ir_analyze_struct_value_field_value(ira, scope, source_node, options, modifier_field); - ZigValue *modifier_val = ir_resolve_const(ira, modifier_inst, UndefBad); - if (modifier_val == nullptr) - return ira->codegen->invalid_inst_gen; - CallModifier modifier = (CallModifier)bigint_as_u32(&modifier_val->data.x_enum_tag); - - if (ir_should_inline(ira->zir, scope)) { - switch (modifier) { - case CallModifierBuiltin: - zig_unreachable(); - case CallModifierAsync: - ir_add_error_node(ira, source_node, buf_sprintf("TODO: comptime @call with async modifier")); - return ira->codegen->invalid_inst_gen; - case CallModifierCompileTime: - case CallModifierNone: - case CallModifierAlwaysInline: - case CallModifierAlwaysTail: - case CallModifierNoSuspend: - modifier = CallModifierCompileTime; - break; - case CallModifierNeverInline: - ir_add_error_node(ira, source_node, - buf_sprintf("unable to perform 'never_inline' call at compile-time")); - return ira->codegen->invalid_inst_gen; - case CallModifierNeverTail: - ir_add_error_node(ira, source_node, - buf_sprintf("unable to perform 'never_tail' call at compile-time")); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *first_arg_ptr = nullptr; - AstNode *first_arg_ptr_src = nullptr; - ZigFn *fn = nullptr; - if (instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - fn = fn_ref->value->data.x_bound_fn.fn; - first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - if (type_is_invalid(first_arg_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - fn = ir_resolve_fn(ira, fn_ref); - } - } - - // Some modifiers require the callee to be comptime-known - switch (modifier) { - case CallModifierCompileTime: - case CallModifierAlwaysInline: - case CallModifierAsync: - if (fn == nullptr) { - ir_add_error(ira, modifier_inst, - buf_sprintf("the specified modifier requires a comptime-known function")); - return ira->codegen->invalid_inst_gen; - } - ZIG_FALLTHROUGH; - default: - break; - } - - ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; - - TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack")); - src_assert(stack_field != nullptr, source_node); - Stage1AirInst *opt_stack = ir_analyze_struct_value_field_value(ira, scope, source_node, options, stack_field); - if (type_is_invalid(opt_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *stack_is_non_null_inst = ir_analyze_test_non_null(ira, scope, source_node, opt_stack); - bool stack_is_non_null; - if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *stack = nullptr; - AstNode *stack_src = nullptr; - if (stack_is_non_null) { - stack = ir_analyze_optional_value_payload_value(ira, scope, source_node, opt_stack, false); - if (type_is_invalid(stack->value->type)) - return ira->codegen->invalid_inst_gen; - stack_src = stack->source_node; - } - - return ir_analyze_fn_call(ira, scope, source_node, fn, fn_type, fn_ref, first_arg_ptr, first_arg_ptr_src, - modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc); -} - -static Stage1AirInst *ir_analyze_async_call_extra(IrAnalyze *ira, Scope *scope, AstNode *source_node, CallModifier modifier, - Stage1ZirInst *pass1_fn_ref, Stage1ZirInst *ret_ptr, Stage1ZirInst *new_stack, Stage1AirInst **args_ptr, size_t args_len, ResultLoc *result_loc) -{ - Stage1AirInst *fn_ref = pass1_fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - if (ir_should_inline(ira->zir, scope)) { - ir_add_error_node(ira, source_node, buf_sprintf("TODO: comptime @asyncCall")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *first_arg_ptr = nullptr; - AstNode *first_arg_ptr_src = nullptr; - ZigFn *fn = nullptr; - if (instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - fn = fn_ref->value->data.x_bound_fn.fn; - first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - if (type_is_invalid(first_arg_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - fn = ir_resolve_fn(ira, fn_ref); - } - } - - Stage1AirInst *ret_ptr_uncasted = nullptr; - if (ret_ptr != nullptr) { - ret_ptr_uncasted = ret_ptr->child; - if (type_is_invalid(ret_ptr_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - } - - ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, - new_stack->child, new_stack->source_node, true, fn); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_fn_call(ira, scope, source_node, fn, fn_type, fn_ref, first_arg_ptr, - first_arg_ptr_src, modifier, casted_new_stack, new_stack->source_node, true, args_ptr, - args_len, ret_ptr_uncasted, result_loc); -} - -static bool ir_extract_tuple_call_args(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *args, Stage1AirInst ***args_ptr, size_t *args_len) { - ZigType *args_type = args->value->type; - if (type_is_invalid(args_type)) - return false; - - if (args_type->id != ZigTypeIdStruct) { - ir_add_error(ira, args, - buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name))); - return false; - } - - if (is_tuple(args_type)) { - *args_len = args_type->data.structure.src_field_count; - *args_ptr = heap::c_allocator.allocate(*args_len); - for (size_t i = 0; i < *args_len; i += 1) { - TypeStructField *arg_field = args_type->data.structure.fields[i]; - (*args_ptr)[i] = ir_analyze_struct_value_field_value(ira, scope, source_node, args, arg_field); - if (type_is_invalid((*args_ptr)[i]->value->type)) - return false; - } - } else { - ir_add_error(ira, args, buf_sprintf("TODO: struct args")); - return false; - } - return true; -} - -static Stage1AirInst *ir_analyze_instruction_call_extra(IrAnalyze *ira, Stage1ZirInstCallExtra *instruction) { - Stage1AirInst *args = instruction->args->child; - Stage1AirInst **args_ptr = nullptr; - size_t args_len = 0; - if (!ir_extract_tuple_call_args(ira, instruction->base.scope, instruction->base.source_node, args, &args_ptr, &args_len)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->options, - instruction->fn_ref, args_ptr, args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_async_call_extra(IrAnalyze *ira, Stage1ZirInstAsyncCallExtra *instruction) { - Stage1AirInst *args = instruction->args->child; - Stage1AirInst **args_ptr = nullptr; - size_t args_len = 0; - if (!ir_extract_tuple_call_args(ira, instruction->base.scope, instruction->base.source_node, args, &args_ptr, &args_len)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_async_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->modifier, - instruction->fn_ref, instruction->ret_ptr, instruction->new_stack, args_ptr, args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_call_args(IrAnalyze *ira, Stage1ZirInstCallArgs *instruction) { - Stage1AirInst **args_ptr = heap::c_allocator.allocate(instruction->args_len); - for (size_t i = 0; i < instruction->args_len; i += 1) { - args_ptr[i] = instruction->args_ptr[i]->child; - if (type_is_invalid(args_ptr[i]->value->type)) - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->options, - instruction->fn_ref, args_ptr, instruction->args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, instruction->args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_call(IrAnalyze *ira, Stage1ZirInstCall *call_instruction) { - Stage1AirInst *fn_ref = call_instruction->fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - bool is_comptime = (call_instruction->modifier == CallModifierCompileTime) || - ir_should_inline(ira->zir, call_instruction->base.scope); - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - - if (is_comptime || instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdMetaType) { - ZigType *ty = ir_resolve_type(ira, fn_ref); - if (ty == nullptr) - return ira->codegen->invalid_inst_gen; - ErrorMsg *msg = ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&ty->name))); - add_error_note(ira->codegen, msg, call_instruction->base.source_node, - buf_sprintf("use @as builtin for type coercion")); - return ira->codegen->invalid_inst_gen; - } else if (fn_ref->value->type->id == ZigTypeIdFn) { - ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref); - ZigType *fn_type = fn_table_entry ? fn_table_entry->type_entry : fn_ref->value->type; - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_type, - fn_ref, nullptr, nullptr, modifier); - } else if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - ZigFn *fn_table_entry = fn_ref->value->data.x_bound_fn.fn; - Stage1AirInst *first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - AstNode *first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, - fn_ref, first_arg_ptr, first_arg_ptr_src, modifier); - } else { - ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (fn_ref->value->type->id == ZigTypeIdFn) { - return ir_analyze_fn_call_src(ira, call_instruction, nullptr, fn_ref->value->type, - fn_ref, nullptr, nullptr, modifier); - } else { - ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -// out_val->type must be the type to read the pointer as -// if the type is different than the actual type then it does a comptime byte reinterpretation -static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *out_val, ZigValue *ptr_val) -{ - Error err; - assert(out_val->type != nullptr); - - ZigValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val); - src_assert(pointee->type != nullptr, source_node); - - if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - - size_t src_size = type_size(codegen, pointee->type); - size_t dst_size = type_size(codegen, out_val->type); - - if (dst_size <= src_size) { - if (src_size == dst_size && types_have_same_zig_comptime_repr(codegen, out_val->type, pointee->type)) { - copy_const_val(codegen, out_val, pointee); - return ErrorNone; - } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - - switch (ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialNull: - if (dst_size == 0) - return ErrorNone; - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer", - dst_size)); - return ErrorSemanticAnalyzeFail; - case ConstPtrSpecialRef: { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; - } - case ConstPtrSpecialSubArray: { - ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; - assert(array_val->type->id == ZigTypeIdArray); - if (array_val->data.x_array.special != ConstArraySpecialNone) - zig_panic("TODO: ir_read_const_ptr ConstPtrSpecialSubArray !ConstArraySpecialNone"); - if (dst_size > src_size) { - size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); - return ErrorSemanticAnalyzeFail; - } - size_t elem_size = src_size; - size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); - Buf buf = BUF_INIT; - buf_resize(&buf, elem_count * elem_size); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); - } - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - case ConstPtrSpecialBaseArray: { - ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; - assert(array_val->type->id == ZigTypeIdArray); - if (array_val->data.x_array.special != ConstArraySpecialNone) - zig_panic("TODO: ir_read_const_ptr ConstPtrSpecialBaseArray !ConstArraySpecialNone"); - size_t elem_size = src_size; - size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; - src_size = elem_size * (array_val->type->data.array.len - elem_index); - if (dst_size > src_size) { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); - return ErrorSemanticAnalyzeFail; - } - size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); - Buf buf = BUF_INIT; - buf_resize(&buf, elem_count * elem_size); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); - } - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - case ConstPtrSpecialBaseStruct: - case ConstPtrSpecialBaseErrorUnionCode: - case ConstPtrSpecialBaseErrorUnionPayload: - case ConstPtrSpecialBaseOptionalPayload: - case ConstPtrSpecialDiscard: - case ConstPtrSpecialHardCodedAddr: - case ConstPtrSpecialFunction: - zig_panic("TODO: ir_read_const_ptr"); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_optional_type(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueOptType *lazy_opt_type = heap::c_allocator.create(); - lazy_opt_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_opt_type->base; - lazy_opt_type->base.id = LazyValueIdOptType; - - lazy_opt_type->payload_type = instruction->value->child; - if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *scalar_type, - ZigValue *operand_val, ZigValue *scalar_out_val, bool is_wrap_op) -{ - bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat); - - bool ok_type = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt || - (is_float && !is_wrap_op); - - if (!ok_type) { - const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; - return ir_add_error_node(ira, source_node, buf_sprintf(fmt, buf_ptr(&scalar_type->name))); - } - - if (is_float) { - float_negate(scalar_out_val, operand_val); - } else if (is_wrap_op) { - bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } else { - bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint); - } - - scalar_out_val->type = scalar_type; - scalar_out_val->special = ConstValSpecialStatic; - - if (is_wrap_op || is_float || scalar_type->id == ZigTypeIdComptimeInt) { - return nullptr; - } - - if (!bigint_fits_in_bits(&scalar_out_val->data.x_bigint, scalar_type->data.integral.bit_count, true)) { - return ir_add_error_node(ira, source_node, buf_sprintf("negation caused overflow")); - } - return nullptr; -} - -static Stage1AirInst *ir_analyze_negation(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *value = instruction->value->child; - ZigType *expr_type = value->value->type; - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); - - ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? - expr_type->data.vector.elem_type : expr_type; - - switch (scalar_type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - break; - case ZigTypeIdInt: - if (is_wrap_op || scalar_type->data.integral.is_signed) - break; - ZIG_FALLTHROUGH; - default: - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("negation of type '%s'", buf_ptr(&scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *operand_val = ir_resolve_const(ira, value, UndefBad); - if (!operand_val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_instruction = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - ZigValue *out_val = result_instruction->value; - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, operand_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = expr_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_operand_val = &operand_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_operand_val->type == scalar_type); - assert(scalar_out_val->type == scalar_type); - ErrorMsg *msg = ir_eval_negation_scalar(ira, instruction->base.scope, instruction->base.source_node, scalar_type, - scalar_operand_val, scalar_out_val, is_wrap_op); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, instruction->base.source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = expr_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_negation_scalar(ira, instruction->base.scope, instruction->base.source_node, scalar_type, operand_val, out_val, - is_wrap_op) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result_instruction; - } - - return ir_build_negation(ira, instruction->base.scope, instruction->base.source_node, value, expr_type, is_wrap_op); -} - -static Stage1AirInst *ir_analyze_bin_not(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *value = instruction->value->child; - ZigType *expr_type = value->value->type; - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? - expr_type->data.vector.elem_type : expr_type; - - if (scalar_type->id != ZigTypeIdInt) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("unable to perform binary not operation on type '%s'", buf_ptr(&expr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *expr_val = ir_resolve_const(ira, value, UndefBad); - if (expr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, expr_val); - result->value->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, result->value); - - for (size_t i = 0; i < expr_type->data.vector.len; i++) { - ZigValue *src_val = &expr_val->data.x_array.data.s_none.elements[i]; - ZigValue *dst_val = &result->value->data.x_array.data.s_none.elements[i]; - - dst_val->type = scalar_type; - dst_val->special = ConstValSpecialStatic; - bigint_not(&dst_val->data.x_bigint, &src_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } - } else { - bigint_not(&result->value->data.x_bigint, &expr_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } - - return result; - } - - return ir_build_binary_not(ira, instruction->base.scope, instruction->base.source_node, value, expr_type); -} - -static Stage1AirInst *ir_analyze_instruction_un_op(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - IrUnOp op_id = instruction->op_id; - switch (op_id) { - case IrUnOpInvalid: - zig_unreachable(); - case IrUnOpBinNot: - return ir_analyze_bin_not(ira, instruction); - case IrUnOpNegation: - case IrUnOpNegationWrap: - return ir_analyze_negation(ira, instruction); - case IrUnOpDereference: { - Stage1AirInst *ptr = instruction->value->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - ZigType *ptr_type = ptr->value->type; - if (ptr_type->id == ZigTypeIdPointer && ptr_type->data.pointer.ptr_len == PtrLenUnknown) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("index syntax required for unknown-length pointer type '%s'", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, ptr, instruction->result_loc); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - - // If the result needs to be an lvalue, type check it - if (instruction->lval != LValNone && result->value->type->id != ZigTypeIdPointer) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", buf_ptr(&result->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return result; - } - case IrUnOpOptional: - return ir_analyze_optional_type(ira, instruction); - } - zig_unreachable(); -} - -static void ir_push_resume(IrAnalyze *ira, IrSuspendPosition pos) { - Stage1ZirBasicBlock *old_bb = ira->zir->basic_block_list.at(pos.basic_block_index); - if (old_bb->in_resume_stack) return; - ira->resume_stack.append(pos); - old_bb->in_resume_stack = true; -} - -static void ir_push_resume_block(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb) { - if (ira->resume_stack.length != 0) { - ir_push_resume(ira, {old_bb->index, 0}); - } -} - -static Stage1AirInst *ir_analyze_instruction_br(IrAnalyze *ira, Stage1ZirInstBr *br_instruction) { - Stage1ZirBasicBlock *old_dest_block = br_instruction->dest_block; - - bool is_comptime; - if (!ir_resolve_comptime(ira, br_instruction->is_comptime->child, &is_comptime)) - return ir_unreach_error(ira); - - if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) - return ir_inline_bb(ira, br_instruction->base.source_node, old_dest_block); - - Stage1AirBasicBlock *new_bb = ir_get_new_bb_runtime(ira, old_dest_block, &br_instruction->base); - if (new_bb == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, old_dest_block); - - Stage1AirInst *result = ir_build_br_gen(ira, br_instruction->base.scope, br_instruction->base.source_node, new_bb); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_cond_br(IrAnalyze *ira, Stage1ZirInstCondBr *cond_br_instruction) { - Stage1AirInst *condition = cond_br_instruction->condition->child; - if (type_is_invalid(condition->value->type)) - return ir_unreach_error(ira); - - bool is_comptime; - if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) - return ir_unreach_error(ira); - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - Stage1AirInst *casted_condition = ir_implicit_cast(ira, condition, bool_type); - if (type_is_invalid(casted_condition->value->type)) - return ir_unreach_error(ira); - - if (is_comptime || instr_is_comptime(casted_condition)) { - bool cond_is_true; - if (!ir_resolve_bool(ira, casted_condition, &cond_is_true)) - return ir_unreach_error(ira); - - Stage1ZirBasicBlock *old_dest_block = cond_is_true ? - cond_br_instruction->then_block : cond_br_instruction->else_block; - - if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) - return ir_inline_bb(ira, cond_br_instruction->base.source_node, old_dest_block); - - Stage1AirBasicBlock *new_dest_block = ir_get_new_bb_runtime(ira, old_dest_block, &cond_br_instruction->base); - if (new_dest_block == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, old_dest_block); - - Stage1AirInst *result = ir_build_br_gen(ira, cond_br_instruction->base.scope, - cond_br_instruction->base.source_node, new_dest_block); - return ir_finish_anal(ira, result); - } - - assert(cond_br_instruction->then_block != cond_br_instruction->else_block); - Stage1AirBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); - if (new_then_block == nullptr) - return ir_unreach_error(ira); - - Stage1AirBasicBlock *new_else_block = ir_get_new_bb_runtime(ira, cond_br_instruction->else_block, &cond_br_instruction->base); - if (new_else_block == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, cond_br_instruction->else_block); - ir_push_resume_block(ira, cond_br_instruction->then_block); - - Stage1AirInst *result = ir_build_cond_br_gen(ira, cond_br_instruction->base.scope, - cond_br_instruction->base.source_node, casted_condition, new_then_block, - new_else_block); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_unreachable(IrAnalyze *ira, - Stage1ZirInstUnreachable *unreachable_instruction) -{ - if (ir_should_inline(ira->zir, unreachable_instruction->base.scope)) { - ir_add_error_node(ira, unreachable_instruction->base.source_node, - buf_sprintf("reached unreachable code")); - return ir_unreach_error(ira); - } - - Stage1AirInst *result = ir_build_unreachable_gen(ira, unreachable_instruction->base.scope, - unreachable_instruction->base.source_node); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_phi(IrAnalyze *ira, Stage1ZirInstPhi *phi_instruction) { - Error err; - - if (ira->const_predecessor_bb) { - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor != ira->const_predecessor_bb) - continue; - Stage1AirInst *value = phi_instruction->incoming_values[i]->child; - assert(value->value->type); - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (value->value->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, phi_instruction->base.scope, - phi_instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, value->value); - return result; - } else { - return value; - } - } - zig_unreachable(); - } - - ResultLocPeerParent *peer_parent = phi_instruction->peer_parent; - if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming && - peer_parent->peers.length >= 2) - { - if (peer_parent->resolved_type == nullptr) { - Stage1AirInst **instructions = heap::c_allocator.allocate(peer_parent->peers.length); - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ResultLocPeer *this_peer = peer_parent->peers.at(i); - - Stage1AirInst *gen_instruction = this_peer->base.gen_instruction; - if (gen_instruction == nullptr) { - // unreachable instructions will cause implicit_elem_type to be null - if (this_peer->base.implicit_elem_type == nullptr) { - instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction->scope, this_peer->base.source_instruction->source_node); - } else { - instructions[i] = ir_const(ira, this_peer->base.source_instruction->scope, - this_peer->base.source_instruction->source_node, - this_peer->base.implicit_elem_type); - instructions[i]->value->special = ConstValSpecialRuntime; - } - } else { - instructions[i] = gen_instruction; - } - - } - ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); - peer_parent->resolved_type = ir_resolve_peer_types(ira, - peer_parent->base.source_instruction->source_node, expected_type, instructions, - peer_parent->peers.length); - if (type_is_invalid(peer_parent->resolved_type)) - return ira->codegen->invalid_inst_gen; - - // the logic below assumes there are no instructions in the new current basic block yet - src_assert(ira->new_irb.current_basic_block->instruction_list.length == 0, - phi_instruction->base.source_node); - - // In case resolving the parent activates a suspend, do it now - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, - peer_parent->resolved_type, nullptr, false, true); - if (parent_result_loc != nullptr && - (type_is_invalid(parent_result_loc->value->type) || parent_result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return parent_result_loc; - } - // If the above code generated any instructions in the current basic block, we need - // to move them to the peer parent predecessor. - ZigList instrs_to_move = {}; - while (ira->new_irb.current_basic_block->instruction_list.length != 0) { - instrs_to_move.append(ira->new_irb.current_basic_block->instruction_list.pop()); - } - if (instrs_to_move.length != 0) { - Stage1AirBasicBlock *predecessor = peer_parent->base.source_instruction->owner_bb->child; - Stage1AirInst *branch_instruction = predecessor->instruction_list.pop(); - src_assert(branch_instruction->value->type->id == ZigTypeIdUnreachable, - phi_instruction->base.source_node); - while (instrs_to_move.length != 0) { - predecessor->instruction_list.append(instrs_to_move.pop()); - } - predecessor->instruction_list.append(branch_instruction); - instrs_to_move.deinit(); - } - } - - IrSuspendPosition suspend_pos; - ira_suspend(ira, &phi_instruction->base, nullptr, &suspend_pos); - ir_push_resume(ira, suspend_pos); - - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ResultLocPeer *opposite_peer = peer_parent->peers.at(peer_parent->peers.length - i - 1); - if (opposite_peer->base.implicit_elem_type != nullptr && - opposite_peer->base.implicit_elem_type->id != ZigTypeIdUnreachable) - { - ir_push_resume(ira, opposite_peer->suspend_pos); - } - } - - peer_parent->done_resuming = true; - return ira_resume(ira); - } - - ZigList new_incoming_blocks = {0}; - ZigList new_incoming_values = {0}; - - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor->ref_count == 0) - continue; - - - Stage1ZirInst *old_value = phi_instruction->incoming_values[i]; - assert(old_value); - Stage1AirInst *new_value = old_value->child; - if (!new_value || new_value->value->type->id == ZigTypeIdUnreachable || predecessor->child == nullptr) - continue; - - if (type_is_invalid(new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - - assert(predecessor->child); - new_incoming_blocks.append(predecessor->child); - new_incoming_values.append(new_value); - } - - if (new_incoming_blocks.length == 0) { - Stage1AirInst *result = ir_build_unreachable_gen(ira, phi_instruction->base.scope, - phi_instruction->base.source_node); - return ir_finish_anal(ira, result); - } - - if (new_incoming_blocks.length == 1) { - Stage1AirInst *incoming_value = new_incoming_values.at(0); - new_incoming_blocks.deinit(); - new_incoming_values.deinit(); - return incoming_value; - } - - ZigType *resolved_type = nullptr; - if (peer_parent != nullptr) { - bool peer_parent_has_type; - if ((err = ir_result_has_type(ira, peer_parent->parent, &peer_parent_has_type))) - return ira->codegen->invalid_inst_gen; - if (peer_parent_has_type) { - if (peer_parent->parent->id == ResultLocIdReturn) { - resolved_type = ira->explicit_return_type; - } else if (peer_parent->parent->id == ResultLocIdCast) { - resolved_type = ir_resolve_type(ira, peer_parent->parent->source_instruction->child); - } else if (peer_parent->parent->resolved_loc) { - ZigType *resolved_loc_ptr_type = peer_parent->parent->resolved_loc->value->type; - src_assert(resolved_loc_ptr_type->id == ZigTypeIdPointer, - phi_instruction->base.source_node); - resolved_type = resolved_loc_ptr_type->data.pointer.child_type; - } - - if (resolved_type != nullptr && type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - } - } - - if (resolved_type == nullptr) { - resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr, - new_incoming_values.items, new_incoming_values.length); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - } - - switch (type_has_one_possible_value(ira->codegen, resolved_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, phi_instruction->base.scope, phi_instruction->base.source_node, - get_the_one_possible_value(ira->codegen, resolved_type)); - case OnePossibleValueNo: - break; - } - - switch (type_requires_comptime(ira->codegen, resolved_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeYes: - ir_add_error_node(ira, phi_instruction->base.source_node, - buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name))); - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); - - // cast all values to the resolved type. however we can't put cast instructions in front of the phi instruction. - // so we go back and insert the casts as the last instruction in the corresponding predecessor blocks, and - // then make sure the branch instruction is preserved. - Stage1AirBasicBlock *cur_bb = ira->new_irb.current_basic_block; - for (size_t i = 0; i < new_incoming_values.length; i += 1) { - Stage1AirInst *new_value = new_incoming_values.at(i); - Stage1AirBasicBlock *predecessor = new_incoming_blocks.at(i); - src_assert(predecessor->instruction_list.length != 0, phi_instruction->base.source_node); - Stage1AirInst *branch_instruction = predecessor->instruction_list.pop(); - ir_set_cursor_at_end_gen(&ira->new_irb, predecessor); - Stage1AirInst *casted_value = ir_implicit_cast(ira, new_value, resolved_type); - if (type_is_invalid(casted_value->value->type)) { - return ira->codegen->invalid_inst_gen; - } - new_incoming_values.items[i] = casted_value; - predecessor->instruction_list.append(branch_instruction); - - if (all_stack_ptrs && (casted_value->value->special != ConstValSpecialRuntime || - casted_value->value->data.rh_ptr != RuntimeHintPtrStack)) - { - all_stack_ptrs = false; - } - } - ir_set_cursor_at_end_gen(&ira->new_irb, cur_bb); - - Stage1AirInst *result = ir_build_phi_gen(ira, phi_instruction->base.scope, - phi_instruction->base.source_node, phi_instruction->merge_comptime, - new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items, resolved_type); - - if (all_stack_ptrs) { - assert(result->value->special == ConstValSpecialRuntime); - result->value->data.rh_ptr = RuntimeHintPtrStack; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_var_ptr(IrAnalyze *ira, Stage1ZirInstVarPtr *instruction) { - ZigVar *var = instruction->var; - Stage1AirInst *result = ir_get_var_ptr(ira, instruction->base.scope, instruction->base.source_node, var); - if (instruction->crossed_fndef_scope != nullptr && !instr_is_comptime(result)) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("'%s' not accessible from inner function", var->name)); - add_error_note(ira->codegen, msg, instruction->crossed_fndef_scope->base.source_node, - buf_sprintf("crossed function definition here")); - add_error_note(ira->codegen, msg, var->decl_node, - buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - new_align, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_sentinel(CodeGen *g, ZigType *ptr_type, ZigValue *new_sentinel) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - new_sentinel); -} - -static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { - assert(is_slice(slice_type)); - ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index]->type_entry, - new_align); - return get_slice_type(g, ptr_type); -} - -static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - (ptr_len != PtrLenUnknown) ? nullptr : ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, - uint64_t elem_index, uint32_t *result) -{ - Error err; - - if (base_ptr_align == 0) { - *result = 0; - return ErrorNone; - } - - // figure out the largest alignment possible - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return err; - - uint64_t elem_size = type_size(ira->codegen, elem_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type); - uint64_t ptr_align = base_ptr_align; - - uint64_t chosen_align = abi_align; - if (ptr_align >= abi_align) { - while (ptr_align > abi_align) { - if ((elem_index * elem_size) % ptr_align == 0) { - chosen_align = ptr_align; - break; - } - ptr_align >>= 1; - } - } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - chosen_align = ptr_align; - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); - } - - *result = chosen_align; - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirInstElemPtr *elem_ptr_instruction) { - Error err; - Stage1AirInst *array_ptr = elem_ptr_instruction->array_ptr->child; - if (type_is_invalid(array_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *elem_index = elem_ptr_instruction->elem_index->child; - if (type_is_invalid(elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *orig_array_ptr_val = array_ptr->value; - - ZigType *ptr_type = orig_array_ptr_val->type; - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *array_type = ptr_type->data.pointer.child_type; - - // At first return_type will be the pointer type we want to return, except with an optimistic alignment. - // We will adjust return_type's alignment before returning it. - ZigType *return_type; - - if (type_is_invalid(array_type)) - return ira->codegen->invalid_inst_gen; - - if (array_type->id == ZigTypeIdPointer && - array_type->data.pointer.ptr_len == PtrLenSingle && - array_type->data.pointer.child_type->id == ZigTypeIdArray) - { - Stage1AirInst *ptr_value = ir_get_deref(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, nullptr); - if (type_is_invalid(ptr_value->value->type)) - return ira->codegen->invalid_inst_gen; - - array_type = array_type->data.pointer.child_type; - ptr_type = ptr_type->data.pointer.child_type; - - orig_array_ptr_val = ptr_value->value; - } - - if (array_type->id == ZigTypeIdArray) { - if(array_type->data.array.len == 0 && array_type->data.array.sentinel == nullptr){ - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("accessing a zero length array is not allowed")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = array_type->data.array.child_type; - if (ptr_type->data.pointer.host_int_bytes == 0) { - return_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - ptr_type->data.pointer.explicit_alignment, 0, 0, false); - } else { - uint64_t elem_val_scalar; - if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) - return ira->codegen->invalid_inst_gen; - - size_t bit_width = type_size_bits(ira->codegen, child_type); - size_t bit_offset = bit_width * elem_val_scalar; - - return_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - 1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes, false); - } - } else if (array_type->id == ZigTypeIdPointer) { - if (array_type->data.pointer.ptr_len == PtrLenSingle) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index of single-item pointer")); - return ira->codegen->invalid_inst_gen; - } - return_type = adjust_ptr_len(ira->codegen, array_type, elem_ptr_instruction->ptr_len); - } else if (is_slice(array_type)) { - return_type = adjust_ptr_len(ira->codegen, array_type->data.structure.fields[slice_ptr_index]->type_entry, - elem_ptr_instruction->ptr_len); - } else if (array_type->id == ZigTypeIdVector) { - // This depends on whether the element index is comptime, so it is computed later. - return_type = nullptr; - } else if (elem_ptr_instruction->init_array_type_source_node != nullptr && - array_type->id == ZigTypeIdStruct && - array_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); - if (type_is_invalid(casted_elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - src_assert(instr_is_comptime(casted_elem_index), elem_ptr_instruction->base.source_node); - Buf *field_name = buf_alloc(); - bigint_append_buf(field_name, &casted_elem_index->value->data.x_bigint, 10); - return ir_analyze_inferred_field_ptr(ira, field_name, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, - array_ptr, array_type); - } else if (is_tuple(array_type)) { - uint64_t elem_index_scalar; - if (!ir_resolve_usize(ira, elem_index, &elem_index_scalar)) - return ira->codegen->invalid_inst_gen; - if (elem_index_scalar >= array_type->data.structure.src_field_count) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf( - "field index %" ZIG_PRI_u64 " outside tuple '%s' which has %" PRIu32 " fields", - elem_index_scalar, buf_ptr(&array_type->name), - array_type->data.structure.src_field_count)); - return ira->codegen->invalid_inst_gen; - } - TypeStructField *field = array_type->data.structure.fields[elem_index_scalar]; - return ir_analyze_struct_field_ptr(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, field, array_ptr, - array_type, false); - } else { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); - if (type_is_invalid(casted_elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - - bool safety_check_on = elem_ptr_instruction->safety_check_on; - if (instr_is_comptime(casted_elem_index)) { - ZigValue *index_val = ir_resolve_const(ira, casted_elem_index, UndefBad); - if (index_val == nullptr) - return ira->codegen->invalid_inst_gen; - uint64_t index = bigint_as_u64(&index_val->data.x_bigint); - - if (array_type->id == ZigTypeIdArray) { - uint64_t array_len = array_type->data.array.len + - (array_type->data.array.sentinel != nullptr); - if (index >= array_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside array of size %" ZIG_PRI_u64, - index, array_len)); - return ira->codegen->invalid_inst_gen; - } - safety_check_on = false; - } else if (array_type->id == ZigTypeIdVector) { - uint64_t vector_len = array_type->data.vector.len; - if (index >= vector_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside vector of size %" ZIG_PRI_u64, - index, vector_len)); - return ira->codegen->invalid_inst_gen; - } - safety_check_on = false; - } - - if (array_type->id == ZigTypeIdVector) { - ZigType *elem_type = array_type->data.vector.elem_type; - uint32_t host_vec_len = array_type->data.vector.len; - return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, - nullptr, nullptr); - } else if (return_type->data.pointer.explicit_alignment != 0) { - uint32_t chosen_align; - if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, - return_type->data.pointer.explicit_alignment, index, &chosen_align))) - { - return ira->codegen->invalid_inst_gen; - } - return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); - } - - // TODO The `array_type->id == ZigTypeIdArray` exception here should not be an exception; - // the `orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar` clause should be omitted completely. - // However there are bugs to fix before this improvement can be made. - if (orig_array_ptr_val->special != ConstValSpecialRuntime && - orig_array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == ZigTypeIdArray)) - { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - elem_ptr_instruction->base.source_node, orig_array_ptr_val, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - - ZigValue *array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, - elem_ptr_instruction->base.source_node); - if (array_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (array_ptr_val->special == ConstValSpecialUndef && - elem_ptr_instruction->init_array_type_source_node != nullptr) - { - if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { - array_ptr_val->data.x_array.special = ConstArraySpecialNone; - array_ptr_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(array_type->data.array.len); - array_ptr_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < array_type->data.array.len; i += 1) { - ZigValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i]; - elem_val->special = ConstValSpecialUndef; - elem_val->type = array_type->data.array.child_type; - elem_val->parent.id = ConstParentIdArray; - elem_val->parent.data.p_array.array_val = array_ptr_val; - elem_val->parent.data.p_array.elem_index = i; - } - } else if (is_slice(array_type)) { - src_assert(array_ptr->value->type->id == ZigTypeIdPointer, elem_ptr_instruction->base.source_node); - ZigType *actual_array_type = array_ptr->value->type->data.pointer.child_type; - - if (type_is_invalid(actual_array_type)) - return ira->codegen->invalid_inst_gen; - if (actual_array_type->id != ZigTypeIdArray) { - ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", - buf_ptr(&actual_array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *array_init_val = ira->codegen->pass1_arena->create(); - array_init_val->special = ConstValSpecialStatic; - array_init_val->type = actual_array_type; - array_init_val->data.x_array.special = ConstArraySpecialNone; - array_init_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(actual_array_type->data.array.len); - array_init_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < actual_array_type->data.array.len; i += 1) { - ZigValue *elem_val = &array_init_val->data.x_array.data.s_none.elements[i]; - elem_val->special = ConstValSpecialUndef; - elem_val->type = actual_array_type->data.array.child_type; - elem_val->parent.id = ConstParentIdArray; - elem_val->parent.data.p_array.array_val = array_init_val; - elem_val->parent.data.p_array.elem_index = i; - } - - init_const_slice(ira->codegen, array_ptr_val, array_init_val, 0, actual_array_type->data.array.len, - false, nullptr); - array_ptr_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutInfer; - } else { - ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, - buf_sprintf("expected array type or [_], found '%s'", - buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (array_ptr_val->special != ConstValSpecialRuntime && - (array_type->id != ZigTypeIdPointer || - array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr)) - { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - elem_ptr_instruction->base.source_node, array_ptr_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - if (array_type->id == ZigTypeIdPointer) { - Stage1AirInst *result = ir_const(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, return_type); - ZigValue *out_val = result->value; - out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - size_t new_index; - size_t mem_size; - size_t old_size; - switch (array_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - if (array_ptr_val->data.x_ptr.data.ref.pointee->type->id == ZigTypeIdArray) { - ZigValue *array_val = array_ptr_val->data.x_ptr.data.ref.pointee; - new_index = index; - ZigType *array_type = array_val->type; - mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { - mem_size += 1; - } - old_size = mem_size; - - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - } else { - mem_size = 1; - old_size = 1; - new_index = index; - - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee; - } - break; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - { - size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; - new_index = offset + index; - ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type; - mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { - mem_size += 1; - } - old_size = mem_size - offset; - - assert(array_ptr_val->data.x_ptr.data.base_array.array_val); - - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = - array_ptr_val->data.x_ptr.data.base_array.array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO elem ptr on a const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO elem ptr on a const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO elem ptr on a const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO elem ptr on a const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO element ptr of a function casted to a ptr"); - case ConstPtrSpecialNull: - zig_panic("TODO elem ptr on a null pointer"); - } - if (new_index >= mem_size) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside pointer of size %" ZIG_PRI_usize "", index, old_size)); - return ira->codegen->invalid_inst_gen; - } - return result; - } else if (is_slice(array_type)) { - expand_undef_struct(ira->codegen, array_ptr_val); - - ZigValue *ptr_field = array_ptr_val->data.x_struct.fields[slice_ptr_index]; - src_assert(ptr_field != nullptr, elem_ptr_instruction->base.source_node); - if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false, - return_type); - } - ZigValue *len_field = array_ptr_val->data.x_struct.fields[slice_len_index]; - Stage1AirInst *result = ir_const(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, return_type); - ZigValue *out_val = result->value; - ZigType *slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint); - uint64_t full_slice_len = slice_len + - ((slice_ptr_type->data.pointer.sentinel != nullptr) ? 1 : 0); - if (index >= full_slice_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, - index, slice_len)); - return ira->codegen->invalid_inst_gen; - } - out_val->data.x_ptr.mut = ptr_field->data.x_ptr.mut; - switch (ptr_field->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - uint64_t array_len = ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len; - if (ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.sentinel != nullptr) { - array_len += 1; - } - size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; - uint64_t new_index = offset + index; - if (ptr_field->data.x_ptr.data.base_array.array_val->data.x_array.special != - ConstArraySpecialBuf) - { - if (new_index >= array_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - } - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = - ptr_field->data.x_ptr.data.base_array.array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO elem ptr on a slice backed by const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO elem ptr on a slice backed by const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO elem ptr on a slice backed by const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO elem ptr on a slice backed by const optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); - case ConstPtrSpecialNull: - zig_panic("TODO elem ptr on a slice has a null pointer"); - } - return result; - } else if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, array_ptr_val); - - Stage1AirInst *result; - if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, - false, return_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, return_type); - } - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut; - out_val->data.x_ptr.data.base_array.array_val = array_ptr_val; - out_val->data.x_ptr.data.base_array.elem_index = index; - return result; - } else { - zig_unreachable(); - } - } - } - } else if (array_type->id == ZigTypeIdVector) { - // runtime known element index - ZigType *elem_type = array_type->data.vector.elem_type; - uint32_t host_vec_len = array_type->data.vector.len; - return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME, - nullptr, nullptr); - } else { - // runtime known element index - switch (type_requires_comptime(ira->codegen, return_type)) { - case ReqCompTimeYes: - ir_add_error(ira, elem_index, - buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known", - buf_ptr(&return_type->data.pointer.child_type->name))); - return ira->codegen->invalid_inst_gen; - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - if (return_type->data.pointer.explicit_alignment != 0) { - if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); - uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); - if (ptr_align < abi_align) { - if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align); - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); - } - } else { - return_type = adjust_ptr_align(ira->codegen, return_type, abi_align); - } - } - } - - return ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on, return_type); -} - -static Stage1AirInst *ir_analyze_container_member_access_inner(IrAnalyze *ira, - ZigType *bare_struct_type, Buf *field_name, Scope *scope, AstNode *source_node, - Stage1AirInst *container_ptr, AstNode *container_ptr_src, ZigType *container_type) -{ - if (!is_slice(bare_struct_type)) { - ScopeDecls *container_scope = get_container_scope(bare_struct_type); - assert(container_scope != nullptr); - auto tld = find_container_decl(ira->codegen, container_scope, field_name); - if (tld) { - if (tld->id == TldIdFn) { - resolve_top_level_decl(ira->codegen, tld, source_node, false); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->invalid_inst_gen; - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - if (tld->visib_mod == VisibModPrivate && - tld->import != get_scope_import(scope)) - { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("'%s' is private", buf_ptr(field_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - assert(fn_entry != nullptr); - - if (type_is_invalid(fn_entry->type_entry)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *bound_fn_value = ir_const_bound_fn(ira, scope, source_node, fn_entry, container_ptr, - container_ptr_src); - return ir_get_ref(ira, scope, source_node, bound_fn_value, true, false); - } else if (tld->id == TldIdVar) { - resolve_top_level_decl(ira->codegen, tld, source_node, false); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->invalid_inst_gen; - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - assert(var != nullptr); - - if (type_is_invalid(var->var_type)) - return ira->codegen->invalid_inst_gen; - - if (var->const_value->type->id == ZigTypeIdFn) { - src_assert(var->const_value->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - ZigFn *fn = var->const_value->data.x_ptr.data.fn.fn_entry; - Stage1AirInst *bound_fn_value = ir_const_bound_fn(ira, scope, source_node, fn, container_ptr, - container_ptr_src); - return ir_get_ref(ira, scope, source_node, bound_fn_value, true, false); - } - } - } - } - const char *prefix_name; - if (is_slice(bare_struct_type)) { - prefix_name = ""; - } else if (bare_struct_type->id == ZigTypeIdStruct) { - prefix_name = "struct "; - } else if (bare_struct_type->id == ZigTypeIdEnum) { - prefix_name = "enum "; - } else if (bare_struct_type->id == ZigTypeIdUnion) { - prefix_name = "union "; - } else if (bare_struct_type->id == ZigTypeIdOpaque) { - prefix_name = "opaque type "; - } else { - prefix_name = ""; - } - ir_add_error_node(ira, source_node, - buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name))); - return ira->codegen->invalid_inst_gen; -} - -static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field) { - if (field->init_val != nullptr) return; - if (field->decl_node == nullptr) return; - if (field->decl_node->type != NodeTypeStructField) return; - AstNode *init_node = field->decl_node->data.struct_field.value; - if (init_node == nullptr) return; - // scope is not the scope of the struct init, it's the scope of the struct type decl - Scope *analyze_scope = &get_container_scope(container_type)->base; - // memoize it - field->init_val = analyze_const_value(codegen, analyze_scope, init_node, - field->type_entry, nullptr, UndefOk); -} - -static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - TypeStructField *field, Stage1AirInst *struct_ptr, ZigType *struct_type, bool initializing) -{ - Error err; - ZigType *field_type = resolve_struct_field_type(ira->codegen, field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - if (field->is_comptime) { - Stage1AirInst *elem = ir_const(ira, scope, source_node, field_type); - memoize_field_init_val(ira->codegen, struct_type, field); - if(field->init_val != nullptr && type_is_invalid(field->init_val->type)){ - return ira->codegen->invalid_inst_gen; - } - copy_const_val(ira->codegen, elem->value, field->init_val); - return ir_get_ref2(ira, scope, source_node, elem, field_type, true, false); - } - switch (type_has_one_possible_value(ira->codegen, field_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: { - Stage1AirInst *elem = ir_const_move(ira, scope, source_node, - get_the_one_possible_value(ira->codegen, field_type)); - return ir_get_ref(ira, scope, source_node, elem, - struct_ptr->value->type->data.pointer.is_const, - struct_ptr->value->type->data.pointer.is_volatile); - } - case OnePossibleValueNo: - break; - } - bool is_const = struct_ptr->value->type->data.pointer.is_const; - bool is_volatile = struct_ptr->value->type->data.pointer.is_volatile; - ZigType *ptr_type; - if (is_anon_container(struct_type)) { - ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - } else { - ResolveStatus needed_resolve_status = - (struct_type->data.structure.layout == ContainerLayoutAuto) ? - ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; - if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) - return ira->codegen->invalid_inst_gen; - assert(struct_ptr->value->type->id == ZigTypeIdPointer); - uint32_t ptr_bit_offset = struct_ptr->value->type->data.pointer.bit_offset_in_host; - uint32_t ptr_host_int_bytes = struct_ptr->value->type->data.pointer.host_int_bytes; - if (ptr_host_int_bytes > 0) { - ptr_bit_offset += field->offset * 8; - } - uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? - get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; - ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, field->align, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - (uint32_t)host_int_bytes_for_result_type, false); - - if (field == struct_type->data.structure.misaligned_field) { - // If field is the last single misaligned field it will be represented as array - // of bytes in LLVM but get_pointer_to_type_extra will set its host_int_bytes to 0. - // We need it not to be 0 so later stage would generate proper bit casting code. - ptr_type->data.pointer.host_int_bytes = host_int_bytes_for_result_type; - } - } - if (instr_is_comptime(struct_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (struct_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (type_is_invalid(struct_val->type)) - return ira->codegen->invalid_inst_gen; - - // This to allow lazy values to be resolved. - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, struct_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - if (initializing && struct_val->special == ConstValSpecialUndef) { - struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); - struct_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { - if (struct_type->data.structure.fields[i]->is_comptime) - continue; - ZigValue *field_val = struct_val->data.x_struct.fields[i]; - field_val->special = ConstValSpecialUndef; - field_val->type = resolve_struct_field_type(ira->codegen, - struct_type->data.structure.fields[i]); - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = struct_val; - field_val->parent.data.p_struct.field_index = i; - } - } - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_struct_field_ptr(ira, scope, source_node, struct_ptr, field, ptr_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, ptr_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - const_val->data.x_ptr.data.base_struct.struct_val = struct_val; - const_val->data.x_ptr.data.base_struct.field_index = field->src_index; - return result; - } - } - return ir_build_struct_field_ptr(ira, scope, source_node, struct_ptr, field, ptr_type); -} - -static Stage1AirInst *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, ZigType *container_type) -{ - // The type of the field is not available until a store using this pointer happens. - // So, here we create a special pointer type which has the inferred struct type and - // field name encoded in the type. Later, when there is a store via this pointer, - // the field type will then be available, and the field will be added to the inferred - // struct. - - ZigType *container_ptr_type = container_ptr->value->type; - src_assert(container_ptr_type->id == ZigTypeIdPointer, source_node); - - InferredStructField *inferred_struct_field = heap::c_allocator.create(); - inferred_struct_field->inferred_struct_type = container_type; - inferred_struct_field->field_name = field_name; - - ZigType *elem_type = ira->codegen->builtin_types.entry_anytype; - ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr); - - if (instr_is_comptime(container_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_cast(ira, scope, source_node, container_ptr_type, container_ptr, CastOpNoop); - } else { - result = ir_const(ira, scope, source_node, field_ptr_type); - } - copy_const_val(ira->codegen, result->value, ptr_val); - result->value->type = field_ptr_type; - return result; - } - - return ir_build_cast(ira, scope, source_node, field_ptr_type, container_ptr, CastOpNoop); -} - -static Stage1AirInst *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, AstNode *container_ptr_src, - ZigType *container_type, bool initializing) -{ - Error err; - - ZigType *bare_type = container_ref_type(container_type); - - if (initializing && bare_type->id == ZigTypeIdStruct && - bare_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - return ir_analyze_inferred_field_ptr(ira, field_name, scope, source_node, container_ptr, bare_type); - } - - // Tracks whether we should return an undefined value of the correct type. - // We do this if the container pointer is undefined and we are in a TypeOf call. - bool return_undef = container_ptr->value->special == ConstValSpecialUndef && \ - get_scope_typeof(scope) != nullptr; - - if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - assert(container_ptr->value->type->id == ZigTypeIdPointer); - if (bare_type->id == ZigTypeIdStruct) { - TypeStructField *field = find_struct_type_field(bare_type, field_name); - if (field != nullptr) { - if (return_undef) { - ZigType *field_ptr_type = get_pointer_to_type(ira->codegen, resolve_struct_field_type(ira->codegen, field), - container_ptr->value->type->data.pointer.is_const); - return ir_const_undef(ira, scope, source_node, field_ptr_type); - } - - return ir_analyze_struct_field_ptr(ira, scope, source_node, field, container_ptr, bare_type, initializing); - } else { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - } - - if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - - if (bare_type->id == ZigTypeIdUnion) { - bool is_const = container_ptr->value->type->data.pointer.is_const; - bool is_volatile = container_ptr->value->type->data.pointer.is_volatile; - - TypeUnionField *field = find_union_type_field(bare_type, field_name); - if (field == nullptr) { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - - ZigType *field_type = resolve_union_field_type(ira->codegen, field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - if (instr_is_comptime(container_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar && - ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (union_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (type_is_invalid(union_val->type)) - return ira->codegen->invalid_inst_gen; - - // Reject undefined values unless we're initializing the union: - // a undefined union means also the tag is undefined, accessing - // its payload slot is UB. - const UndefAllowed allow_undef = initializing ? UndefOk : UndefBad; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, union_val, allow_undef))) - { - return ira->codegen->invalid_inst_gen; - } - - if (initializing) { - ZigValue *payload_val = ira->codegen->pass1_arena->create(); - payload_val->special = ConstValSpecialUndef; - payload_val->type = field_type; - payload_val->parent.id = ConstParentIdUnion; - payload_val->parent.data.p_union.union_val = union_val; - - union_val->special = ConstValSpecialStatic; - bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); - union_val->data.x_union.payload = payload_val; - } else if (bare_type->data.unionation.layout != ContainerLayoutExtern) { - TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); - if (actual_field == nullptr) - zig_unreachable(); - - if (field != actual_field) { - ir_add_error_node(ira, source_node, - buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), - buf_ptr(actual_field->name))); - return ira->codegen->invalid_inst_gen; - } - } - - ZigValue *payload_val = union_val->data.x_union.payload; - assert(payload_val); - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_union_field_ptr(ira, scope, source_node, container_ptr, field, true, - initializing, ptr_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, ptr_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.mut = container_ptr->value->data.x_ptr.mut; - const_val->data.x_ptr.data.ref.pointee = payload_val; - return result; - } - } - - return ir_build_union_field_ptr(ira, scope, source_node, container_ptr, field, true, initializing, ptr_type); - } - - zig_unreachable(); -} - -static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) { - const char *msg = stage2_add_link_lib(&ira->codegen->stage1, buf_ptr(lib_name), buf_len(lib_name), - buf_ptr(symbol_name), buf_len(symbol_name)); - if (msg != nullptr) { - ir_add_error_node(ira, source_node, buf_create_from_str(msg)); - ira->codegen->reported_bad_link_libc_error = true; - } -} - -static Stage1AirInst *ir_error_dependency_loop(IrAnalyze *ira, AstNode* source_node) { - ir_add_error_node(ira, source_node, buf_sprintf("dependency loop detected")); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_decl_ref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Tld *tld) { - resolve_top_level_decl(ira->codegen, tld, source_node, true); - if (tld->resolution == TldResolutionInvalid) { - return ira->codegen->invalid_inst_gen; - } - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - switch (tld->id) { - case TldIdContainer: - case TldIdCompTime: - case TldIdUsingNamespace: - zig_unreachable(); - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - assert(var != nullptr); - - if (tld_var->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_var->extern_lib_name, buf_create_from_str(var->name), - source_node); - } - - return ir_get_var_ptr(ira, scope, source_node, var); - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - assert(fn_entry->type_entry != nullptr); - - if (type_is_invalid(fn_entry->type_entry)) - return ira->codegen->invalid_inst_gen; - - if (tld_fn->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_node); - } - - Stage1AirInst *fn_inst = ir_const_fn(ira, scope, source_node, fn_entry); - return ir_get_ref(ira, scope, source_node, fn_inst, true, false); - } - } - zig_unreachable(); -} - -static ErrorTableEntry *find_err_table_entry(ZigType *err_set_type, Buf *field_name) { - assert(err_set_type->id == ZigTypeIdErrorSet); - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *err_table_entry = err_set_type->data.error_set.errors[i]; - if (buf_eql_buf(&err_table_entry->name, field_name)) { - return err_table_entry; - } - } - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_field_ptr(IrAnalyze *ira, Stage1ZirInstFieldPtr *field_ptr_instruction) { - Error err; - Stage1AirInst *container_ptr = field_ptr_instruction->container_ptr->child; - if (type_is_invalid(container_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *container_type = container_ptr->value->type->data.pointer.child_type; - - Buf *field_name = field_ptr_instruction->field_name_buffer; - if (!field_name) { - Stage1AirInst *field_name_expr = field_ptr_instruction->field_name_expr->child; - field_name = ir_resolve_str(ira, field_name_expr); - if (!field_name) - return ira->codegen->invalid_inst_gen; - } - - - AstNode *source_node = field_ptr_instruction->base.source_node; - - if (type_is_invalid(container_type)) { - return ira->codegen->invalid_inst_gen; - } else if (is_tuple(container_type) && !field_ptr_instruction->initializing && buf_eql_str(field_name, "len")) { - Stage1AirInst *len_inst = ir_const_unsigned(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_type->data.structure.src_field_count); - return ir_get_ref(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, len_inst, true, false); - } else if (is_slice(container_type) || is_container_ref(container_type)) { - assert(container_ptr->value->type->id == ZigTypeIdPointer); - if (container_type->id == ZigTypeIdPointer) { - ZigType *bare_type = container_ref_type(container_type); - Stage1AirInst *container_child = ir_get_deref(ira, field_ptr_instruction->base.scope, - field_ptr_instruction->base.source_node, container_ptr, nullptr); - Stage1AirInst *result = ir_analyze_container_field_ptr(ira, field_name, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_child, field_ptr_instruction->container_ptr->source_node, bare_type, - field_ptr_instruction->initializing); - return result; - } else { - Stage1AirInst *result = ir_analyze_container_field_ptr(ira, field_name, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_ptr, field_ptr_instruction->container_ptr->source_node, - container_type, field_ptr_instruction->initializing); - return result; - } - } else if (is_array_ref(container_type) && !field_ptr_instruction->initializing) { - if (buf_eql_str(field_name, "len")) { - ZigValue *len_val = ira->codegen->pass1_arena->create(); - if (container_type->id == ZigTypeIdPointer) { - init_const_usize(ira->codegen, len_val, container_type->data.pointer.child_type->data.array.len); - } else { - init_const_usize(ira->codegen, len_val, container_type->data.array.len); - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, len_val, - usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("no field named '%s' in '%s'", buf_ptr(field_name), - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (container_type->id == ZigTypeIdMetaType) { - ZigValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!container_ptr_val) - return ira->codegen->invalid_inst_gen; - - assert(container_ptr->value->type->id == ZigTypeIdPointer); - ZigValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); - if (child_val == nullptr) - return ira->codegen->invalid_inst_gen; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - field_ptr_instruction->base.source_node, child_val, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - ZigType *child_type = child_val->data.x_type; - - if (type_is_invalid(child_type)) { - return ira->codegen->invalid_inst_gen; - } else if (is_container(child_type)) { - if (child_type->id == ZigTypeIdEnum) { - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_type_field(child_type, field_name); - if (field) { - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - create_const_enum(ira->codegen, child_type, &field->value), child_type, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } - } - ScopeDecls *container_scope = get_container_scope(child_type); - Tld *tld = find_container_decl(ira->codegen, container_scope, field_name); - if (tld) { - if (tld->visib_mod == VisibModPrivate && - tld->import != get_scope_import(field_ptr_instruction->base.scope)) - { - ErrorMsg *msg = ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("'%s' is private", buf_ptr(field_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - return ir_analyze_decl_ref(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, tld); - } - if (is_tagged_union(child_type)) { - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - TypeUnionField *field = find_union_type_field(child_type, field_name); - if (field) { - ZigType *enum_type = child_type->data.unionation.tag_type; - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - create_const_enum(ira->codegen, enum_type, &field->enum_field->value), enum_type, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } - } - const char *container_name = (child_type == ira->codegen->root_import) ? - "root source file" : buf_ptr(buf_sprintf("container '%s'", buf_ptr(&child_type->name))); - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("%s has no member called '%s'", - container_name, buf_ptr(field_name))); - return ira->codegen->invalid_inst_gen; - } else if (child_type->id == ZigTypeIdErrorSet) { - ErrorTableEntry *err_entry; - ZigType *err_set_type; - if (type_is_global_error_set(child_type)) { - auto existing_entry = ira->codegen->error_table.maybe_get(field_name); - if (existing_entry) { - err_entry = existing_entry->value; - } else { - err_entry = heap::c_allocator.create(); - err_entry->decl_node = field_ptr_instruction->base.source_node; - buf_init_from_buf(&err_entry->name, field_name); - size_t error_value_count = ira->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); - err_entry->value = error_value_count; - ira->codegen->errors_by_index.append(err_entry); - ira->codegen->error_table.put(field_name, err_entry); - } - if (err_entry->set_with_only_this_in_it == nullptr) { - err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - err_entry); - } - err_set_type = err_entry->set_with_only_this_in_it; - } else { - if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - err_entry = find_err_table_entry(child_type, field_name); - if (err_entry == nullptr) { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name))); - return ira->codegen->invalid_inst_gen; - } - err_set_type = child_type; - } - ZigValue *const_val = ira->codegen->pass1_arena->create(); - const_val->special = ConstValSpecialStatic; - const_val->type = err_set_type; - const_val->data.x_err_set = err_entry; - - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, - field_ptr_instruction->base.source_node, const_val, - err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } else { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (field_ptr_instruction->initializing) { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support struct initialization syntax", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -static Stage1AirInst *ir_analyze_instruction_store_ptr(IrAnalyze *ira, Stage1ZirInstStorePtr *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, ptr, value, instruction->allow_write_through_const); -} - -static Stage1AirInst *ir_analyze_instruction_load_ptr(IrAnalyze *ira, Stage1ZirInstLoadPtr *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_instruction_typeof(IrAnalyze *ira, Stage1ZirInstTypeOf *typeof_instruction) { - ZigType *type_entry; - - const size_t value_count = typeof_instruction->value_count; - - // Fast path for the common case of TypeOf with a single argument - if (value_count < 2) { - type_entry = typeof_instruction->value.scalar->child->value->type; - } else { - Stage1AirInst **args = heap::c_allocator.allocate(value_count); - for (size_t i = 0; i < value_count; i += 1) { - Stage1AirInst *value = typeof_instruction->value.list[i]->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - args[i] = value; - } - - type_entry = ir_resolve_peer_types(ira, typeof_instruction->base.source_node, - nullptr, args, value_count); - - heap::c_allocator.deallocate(args, value_count); - } - - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - return ir_const_type(ira, typeof_instruction->base.scope, typeof_instruction->base.source_node, type_entry); -} - -static Stage1AirInst *ir_analyze_instruction_set_cold(IrAnalyze *ira, Stage1ZirInstSetCold *instruction) { - if (ira->new_irb.exec->is_inline) { - // ignore setCold when running functions at compile time - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - Stage1AirInst *is_cold_value = instruction->is_cold->child; - bool want_cold; - if (!ir_resolve_bool(ira, is_cold_value, &want_cold)) - return ira->codegen->invalid_inst_gen; - - ZigFn *fn_entry = scope_fn_entry(instruction->base.scope); - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setCold outside function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->set_cold_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cold set twice in same function")); - add_error_note(ira->codegen, msg, fn_entry->set_cold_node, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - - fn_entry->set_cold_node = instruction->base.source_node; - fn_entry->is_cold = want_cold; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira, - Stage1ZirInstSetRuntimeSafety *set_runtime_safety_instruction) -{ - if (ira->new_irb.exec->is_inline) { - // ignore setRuntimeSafety when running functions at compile time - return ir_const_void(ira, set_runtime_safety_instruction->base.scope, - set_runtime_safety_instruction->base.source_node); - } - - bool *safety_off_ptr; - AstNode **safety_set_node_ptr; - - Scope *scope = set_runtime_safety_instruction->base.scope; - while (scope != nullptr) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - safety_off_ptr = &block_scope->safety_off; - safety_set_node_ptr = &block_scope->safety_set_node; - break; - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *def_scope = (ScopeFnDef *)scope; - ZigFn *target_fn = def_scope->fn_entry; - assert(target_fn->def_scope != nullptr); - safety_off_ptr = &target_fn->def_scope->safety_off; - safety_set_node_ptr = &target_fn->def_scope->safety_set_node; - break; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - safety_off_ptr = &decls_scope->safety_off; - safety_set_node_ptr = &decls_scope->safety_set_node; - break; - } else { - scope = scope->parent; - continue; - } - } - assert(scope != nullptr); - - Stage1AirInst *safety_on_value = set_runtime_safety_instruction->safety_on->child; - bool want_runtime_safety; - if (!ir_resolve_bool(ira, safety_on_value, &want_runtime_safety)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = set_runtime_safety_instruction->base.source_node; - if (*safety_set_node_ptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("runtime safety set twice for same scope")); - add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - *safety_set_node_ptr = source_node; - *safety_off_ptr = !want_runtime_safety; - - return ir_const_void(ira, set_runtime_safety_instruction->base.scope, - set_runtime_safety_instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, - Stage1ZirInstSetFloatMode *instruction) -{ - if (ira->new_irb.exec->is_inline) { - // ignore setFloatMode when running functions at compile time - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - bool *fast_math_on_ptr; - AstNode **fast_math_set_node_ptr; - - Scope *scope = instruction->base.scope; - while (scope != nullptr) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - fast_math_on_ptr = &block_scope->fast_math_on; - fast_math_set_node_ptr = &block_scope->fast_math_set_node; - break; - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *def_scope = (ScopeFnDef *)scope; - ZigFn *target_fn = def_scope->fn_entry; - assert(target_fn->def_scope != nullptr); - fast_math_on_ptr = &target_fn->def_scope->fast_math_on; - fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node; - break; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - fast_math_on_ptr = &decls_scope->fast_math_on; - fast_math_set_node_ptr = &decls_scope->fast_math_set_node; - break; - } else { - scope = scope->parent; - continue; - } - } - assert(scope != nullptr); - - Stage1AirInst *float_mode_value = instruction->mode_value->child; - FloatMode float_mode_scalar; - if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = instruction->base.source_node; - if (*fast_math_set_node_ptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("float mode set twice for same scope")); - add_error_note(ira->codegen, msg, *fast_math_set_node_ptr, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - *fast_math_set_node_ptr = source_node; - *fast_math_on_ptr = (float_mode_scalar == FloatModeOptimized); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, Stage1ZirInstAnyFrameType *instruction) { - ZigType *payload_type = nullptr; - if (instruction->payload_type != nullptr) { - payload_type = ir_resolve_type(ira, instruction->payload_type->child); - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen; - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, payload_type); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, any_frame_type); -} - -static Stage1AirInst *ir_analyze_instruction_slice_type(IrAnalyze *ira, Stage1ZirInstSliceType *slice_type_instruction) { - Stage1AirInst *result = ir_const(ira, slice_type_instruction->base.scope, - slice_type_instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueSliceType *lazy_slice_type = heap::c_allocator.create(); - lazy_slice_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_slice_type->base; - lazy_slice_type->base.id = LazyValueIdSliceType; - - if (slice_type_instruction->align_value != nullptr) { - lazy_slice_type->align_inst = slice_type_instruction->align_value->child; - if (ir_resolve_const(ira, lazy_slice_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - if (slice_type_instruction->sentinel != nullptr) { - lazy_slice_type->sentinel = slice_type_instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_slice_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_slice_type->elem_type = slice_type_instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_slice_type->is_const = slice_type_instruction->is_const; - lazy_slice_type->is_volatile = slice_type_instruction->is_volatile; - lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero; - - return result; -} - -static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { - const char *ptr = buf_ptr(src_template) + tok->start + 2; - size_t len = tok->end - tok->start - 2; - size_t result = 0; - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { - return result; - } - } - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { - return result; - } - } - return SIZE_MAX; -} - -static Stage1AirInst *ir_analyze_instruction_asm(IrAnalyze *ira, Stage1ZirInstAsm *asm_instruction) { - Error err; - - assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); - - AstNode *node = asm_instruction->base.source_node; - AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; - - Buf *template_buf = ir_resolve_str(ira, asm_instruction->asm_template->child); - if (template_buf == nullptr) - return ira->codegen->invalid_inst_gen; - - if (asm_instruction->is_global) { - buf_append_char(&ira->codegen->global_asm, '\n'); - buf_append_buf(&ira->codegen->global_asm, template_buf); - - return ir_const_void(ira, asm_instruction->base.scope, asm_instruction->base.source_node); - } - - if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base)) - return ira->codegen->invalid_inst_gen; - - ZigList tok_list = {}; - if ((err = parse_asm_template(ira, node, template_buf, &tok_list))) { - return ira->codegen->invalid_inst_gen; - } - - for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { - AsmToken asm_token = tok_list.at(token_i); - if (asm_token.id == AsmTokenIdVar) { - size_t index = find_asm_index(ira->codegen, node, &asm_token, template_buf); - if (index == SIZE_MAX) { - const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; - uint32_t len = asm_token.end - asm_token.start - 2; - - add_node_error(ira->codegen, node, - buf_sprintf("could not find '%.*s' in the inputs or outputs", - len, ptr)); - return ira->codegen->invalid_inst_gen; - } - } - } - - // TODO validate the output types and variable types - - Stage1AirInst **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); - Stage1AirInst **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); - - ZigType *return_type = ira->codegen->builtin_types.entry_void; - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (asm_output->return_type) { - output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i]); - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - } - } - - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - Stage1AirInst *const input_value = asm_instruction->input_list[i]->child; - if (type_is_invalid(input_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(input_value) && - (input_value->value->type->id == ZigTypeIdComptimeInt || - input_value->value->type->id == ZigTypeIdComptimeFloat)) { - ir_add_error(ira, input_value, - buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - input_list[i] = input_value; - } - - return ir_build_asm_gen(ira, asm_instruction->base.scope, asm_instruction->base.source_node, - template_buf, tok_list.items, tok_list.length, - input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count, - asm_instruction->has_side_effects, return_type); -} - -static Stage1AirInst *ir_analyze_instruction_array_type(IrAnalyze *ira, Stage1ZirInstArrayType *array_type_instruction) { - Stage1AirInst *result = ir_const(ira, array_type_instruction->base.scope, - array_type_instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueArrayType *lazy_array_type = heap::c_allocator.create(); - lazy_array_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_array_type->base; - lazy_array_type->base.id = LazyValueIdArrayType; - - lazy_array_type->elem_type = array_type_instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_array_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!ir_resolve_usize(ira, array_type_instruction->size->child, &lazy_array_type->length)) - return ira->codegen->invalid_inst_gen; - - if (array_type_instruction->sentinel != nullptr) { - lazy_array_type->sentinel = array_type_instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_array_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_size_of(IrAnalyze *ira, Stage1ZirInstSizeOf *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - result->value->special = ConstValSpecialLazy; - - LazyValueSizeOf *lazy_size_of = heap::c_allocator.create(); - lazy_size_of->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_size_of->base; - lazy_size_of->base.id = LazyValueIdSizeOf; - lazy_size_of->bit_size = instruction->bit_size; - - lazy_size_of->target_type = instruction->type_value->child; - if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_test_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - ZigType *type_entry = value->value->type; - - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.allow_zero) { - if (instr_is_comptime(value)) { - ZigValue *c_ptr_val = ir_resolve_const(ira, value, UndefOk); - if (c_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (c_ptr_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - return ir_const_bool(ira, scope, source_node, !is_null); - } - - return ir_build_test_non_null_gen(ira, scope, source_node, value); - } else if (type_entry->id == ZigTypeIdOptional) { - if (instr_is_comptime(value)) { - ZigValue *maybe_val = ir_resolve_const(ira, value, UndefOk); - if (maybe_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (maybe_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - - return ir_const_bool(ira, scope, source_node, !optional_value_is_null(maybe_val)); - } - - return ir_build_test_non_null_gen(ira, scope, source_node, value); - } else if (type_entry->id == ZigTypeIdNull) { - return ir_const_bool(ira, scope, source_node, false); - } else { - return ir_const_bool(ira, scope, source_node, true); - } -} - -static Stage1AirInst *ir_analyze_instruction_test_non_null(IrAnalyze *ira, Stage1ZirInstTestNonNull *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, value); -} - -static Stage1AirInst *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing) -{ - Error err; - - ZigType *type_entry = get_ptr_elem_type(ira->codegen, base_ptr); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.ptr_len == PtrLenC) { - if (instr_is_comptime(base_ptr)) { - ZigValue *val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *c_ptr_val = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (c_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - if (is_null) { - ir_add_error_node(ira, source_node, buf_sprintf("unable to unwrap null")); - return ira->codegen->invalid_inst_gen; - } - return base_ptr; - } - } - if (!safety_check_on) - return base_ptr; - Stage1AirInst *c_ptr_val = ir_get_deref(ira, scope, source_node, base_ptr, nullptr); - ir_build_assert_non_null(ira, scope, source_node, c_ptr_val); - return base_ptr; - } - - if (type_entry->id != ZigTypeIdOptional) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = type_entry->data.maybe.child_type; - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, - base_ptr->value->type->data.pointer.is_const, base_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false); - - bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *optional_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (optional_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (initializing) { - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - if (!same_comptime_repr) { - ZigValue *payload_val = ira->codegen->pass1_arena->create(); - payload_val->type = child_type; - payload_val->special = ConstValSpecialUndef; - payload_val->parent.id = ConstParentIdOptionalPayload; - payload_val->parent.data.p_optional_payload.optional_val = optional_val; - - optional_val->data.x_optional = payload_val; - optional_val->special = ConstValSpecialStatic; - } - break; - case OnePossibleValueYes: { - optional_val->special = ConstValSpecialStatic; - optional_val->data.x_optional = get_the_one_possible_value(ira->codegen, child_type); - break; - } - } - } else { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, optional_val, UndefBad))) - return ira->codegen->invalid_inst_gen; - if (optional_value_is_null(optional_val)) { - ir_add_error_node(ira, source_node, buf_sprintf("unable to unwrap null")); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_optional_unwrap_ptr_gen(ira, scope, source_node, base_ptr, false, - initializing, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - ZigValue *result_val = result->value; - result_val->data.x_ptr.special = ConstPtrSpecialRef; - result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - if (same_comptime_repr) { - result_val->data.x_ptr.data.ref.pointee = optional_val; - } else { - assert(optional_val->data.x_optional != nullptr); - result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; - } - break; - case OnePossibleValueYes: - assert(optional_val->data.x_optional != nullptr); - result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; - break; - } - return result; - } - } - - return ir_build_optional_unwrap_ptr_gen(ira, scope, source_node, base_ptr, safety_check_on, - initializing, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, - Stage1ZirInstOptionalUnwrapPtr *instruction) -{ - Stage1AirInst *base_ptr = instruction->base_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_unwrap_optional_payload(ira, instruction->base.scope, instruction->base.source_node, base_ptr, - instruction->safety_check_on, false); -} - -static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - size_t value = bigint_ctz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - size_t value = bigint_clz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1ZirInstPopCount *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - - if (bigint_cmp_zero(&op_elem_val->data.x_bigint) != CmpLT) { - size_t value = bigint_popcount_unsigned(&op_elem_val->data.x_bigint); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - size_t value = bigint_popcount_signed(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) { - size_t result = bigint_popcount_unsigned(&val->data.x_bigint); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); - } - size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_pop_count_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_union_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (value->value->type->id != ZigTypeIdUnion) { - ir_add_error(ira, value, - buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (!value->value->type->data.unionation.have_explicit_tag_type) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("union has no associated enum")); - if (value->value->type->data.unionation.decl_node != nullptr) { - add_error_note(ira->codegen, msg, value->value->type->data.unionation.decl_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - ZigType *tag_type = value->value->type->data.unionation.tag_type; - assert(tag_type->id == ZigTypeIdEnum); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = tag_type; - const_instruction->base.value->special = ConstValSpecialStatic; - bigint_init_bigint(&const_instruction->base.value->data.x_enum_tag, &val->data.x_union.tag); - return &const_instruction->base; - } - - return ir_build_union_tag(ira, scope, source_node, value, tag_type); -} - -static Stage1AirInst *ir_analyze_instruction_switch_br(IrAnalyze *ira, - Stage1ZirInstSwitchBr *switch_br_instruction) -{ - Stage1AirInst *target_value = switch_br_instruction->target_value->child; - if (type_is_invalid(target_value->value->type)) - return ir_unreach_error(ira); - - if (switch_br_instruction->switch_prongs_void != nullptr) { - if (type_is_invalid(switch_br_instruction->switch_prongs_void->child->value->type)) { - return ir_unreach_error(ira); - } - } - - - size_t case_count = switch_br_instruction->case_count; - - bool is_comptime; - if (!ir_resolve_comptime(ira, switch_br_instruction->is_comptime->child, &is_comptime)) - return ira->codegen->invalid_inst_gen; - - if (is_comptime || instr_is_comptime(target_value)) { - ZigValue *target_val = ir_resolve_const(ira, target_value, UndefBad); - if (!target_val) - return ir_unreach_error(ira); - - Stage1ZirBasicBlock *old_dest_block = switch_br_instruction->else_block; - for (size_t i = 0; i < case_count; i += 1) { - Stage1ZirInstSwitchBrCase *old_case = &switch_br_instruction->cases[i]; - Stage1AirInst *case_value = old_case->value->child; - if (type_is_invalid(case_value->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value->type); - if (type_is_invalid(casted_case_value->value->type)) - return ir_unreach_error(ira); - - ZigValue *case_val = ir_resolve_const(ira, casted_case_value, UndefBad); - if (!case_val) - return ir_unreach_error(ira); - - if (const_values_equal(ira->codegen, target_val, case_val)) { - old_dest_block = old_case->block; - break; - } - } - - if (is_comptime || old_dest_block->ref_count == 1) { - return ir_inline_bb(ira, switch_br_instruction->base.source_node, old_dest_block); - } else { - Stage1AirBasicBlock *new_dest_block = ir_get_new_bb(ira, old_dest_block, &switch_br_instruction->base); - Stage1AirInst *result = ir_build_br_gen(ira, switch_br_instruction->base.scope, - switch_br_instruction->base.source_node, new_dest_block); - return ir_finish_anal(ira, result); - } - } - - Stage1AirInstSwitchBrCase *cases = heap::c_allocator.allocate(case_count); - for (size_t i = 0; i < case_count; i += 1) { - Stage1ZirInstSwitchBrCase *old_case = &switch_br_instruction->cases[i]; - Stage1AirInstSwitchBrCase *new_case = &cases[i]; - new_case->block = ir_get_new_bb(ira, old_case->block, &switch_br_instruction->base); - new_case->value = ira->codegen->invalid_inst_gen; - - // Calling ir_get_new_bb set the ref_instruction on the new basic block. - // However a switch br may branch to the same basic block which would trigger an - // incorrect re-generation of the block. So we set it to null here and assign - // it back after the loop. - new_case->block->ref_instruction = nullptr; - - Stage1ZirInst *old_value = old_case->value; - Stage1AirInst *new_value = old_value->child; - if (type_is_invalid(new_value->value->type)) - continue; - - Stage1AirInst *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value->type); - if (type_is_invalid(casted_new_value->value->type)) - continue; - - if (!ir_resolve_const(ira, casted_new_value, UndefBad)) - continue; - - new_case->value = casted_new_value; - } - - for (size_t i = 0; i < case_count; i += 1) { - Stage1AirInstSwitchBrCase *new_case = &cases[i]; - if (type_is_invalid(new_case->value->value->type)) - return ir_unreach_error(ira); - new_case->block->ref_instruction = &switch_br_instruction->base; - } - - Stage1AirBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base); - Stage1AirInstSwitchBr *switch_br = ir_build_switch_br_gen(ira, switch_br_instruction->base.scope, - switch_br_instruction->base.source_node, target_value, new_else_block, case_count, cases); - return ir_finish_anal(ira, &switch_br->base); -} - -static Stage1AirInst *ir_analyze_instruction_switch_target(IrAnalyze *ira, - Stage1ZirInstSwitchTarget *switch_target_instruction) -{ - Error err; - Stage1AirInst *target_value_ptr = switch_target_instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target_value_ptr->value->type->id == ZigTypeIdMetaType) { - assert(instr_is_comptime(target_value_ptr)); - ZigType *ptr_type = target_value_ptr->value->data.x_type; - assert(ptr_type->id == ZigTypeIdPointer); - return ir_const_type(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, ptr_type->data.pointer.child_type); - } - - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - ZigValue *pointee_val = nullptr; - if (instr_is_comptime(target_value_ptr) && target_value_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - pointee_val = const_ptr_pointee(ira, ira->codegen, target_value_ptr->value, target_value_ptr->source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (pointee_val->special == ConstValSpecialRuntime) - pointee_val = nullptr; - } - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - switch (target_type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdErrorSet: { - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, pointee_val); - result->value->type = target_type; - return result; - } - - Stage1AirInst *result = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - result->value->type = target_type; - return result; - } - case ZigTypeIdUnion: { - AstNode *decl_node = target_type->data.unionation.decl_node; - if (!decl_node->data.container_decl.auto_enum && - decl_node->data.container_decl.init_arg_expr == nullptr) - { - ErrorMsg *msg = ir_add_error(ira, target_value_ptr, - buf_sprintf("switch on union which has no attached enum")); - add_error_note(ira->codegen, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - return ira->codegen->invalid_inst_gen; - } - ZigType *tag_type = target_type->data.unionation.tag_type; - assert(tag_type != nullptr); - assert(tag_type->id == ZigTypeIdEnum); - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, tag_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_union.tag); - return result; - } - - if (can_fold_enum_type(tag_type)) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, tag_type); - TypeEnumField *only_field = &tag_type->data.enumeration.fields[0]; - bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); - return result; - } - - Stage1AirInst *union_value = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - union_value->value->type = target_type; - - return ir_build_union_tag(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, union_value, tag_type); - } - case ZigTypeIdEnum: { - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (can_fold_enum_type(target_type)) { - TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, target_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); - return result; - } - - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, target_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_enum_tag); - return result; - } - - Stage1AirInst *enum_value = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - enum_value->value->type = target_type; - return enum_value; - } - case ZigTypeIdErrorUnion: - case ZigTypeIdUnreachable: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error_node(ira, switch_target_instruction->base.source_node, - buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_switch_var(IrAnalyze *ira, Stage1ZirInstSwitchVar *instruction) { - Stage1AirInst *target_value_ptr = instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ref_type = target_value_ptr->value->type; - assert(ref_type->id == ZigTypeIdPointer); - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - if (target_type->id == ZigTypeIdUnion) { - ZigType *enum_type = target_type->data.unionation.tag_type; - assert(enum_type != nullptr); - assert(enum_type->id == ZigTypeIdEnum); - assert(instruction->prongs_len > 0); - - Stage1AirInst *first_prong_value = instruction->prongs_ptr[0]->child; - if (type_is_invalid(first_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *first_casted_prong_value = ir_implicit_cast(ira, first_prong_value, enum_type); - if (type_is_invalid(first_casted_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *first_prong_val = ir_resolve_const(ira, first_casted_prong_value, UndefBad); - if (first_prong_val == nullptr) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *first_field = find_union_field_by_tag(target_type, &first_prong_val->data.x_enum_tag); - - ErrorMsg *invalid_payload_msg = nullptr; - for (size_t prong_i = 1; prong_i < instruction->prongs_len; prong_i += 1) { - Stage1AirInst *this_prong_inst = instruction->prongs_ptr[prong_i]->child; - if (type_is_invalid(this_prong_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *this_casted_prong_value = ir_implicit_cast(ira, this_prong_inst, enum_type); - if (type_is_invalid(this_casted_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *this_prong = ir_resolve_const(ira, this_casted_prong_value, UndefBad); - if (this_prong == nullptr) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *payload_field = find_union_field_by_tag(target_type, &this_prong->data.x_enum_tag); - ZigType *payload_type = payload_field->type_entry; - if (first_field->type_entry != payload_type) { - if (invalid_payload_msg == nullptr) { - invalid_payload_msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("capture group with incompatible types")); - add_error_note(ira->codegen, invalid_payload_msg, first_prong_value->source_node, - buf_sprintf("type '%s' here", buf_ptr(&first_field->type_entry->name))); - } - add_error_note(ira->codegen, invalid_payload_msg, this_prong_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&payload_field->type_entry->name))); - } - } - - if (invalid_payload_msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target_value_ptr)) { - ZigValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad); - if (!target_value_ptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *pointee_val = const_ptr_pointee(ira, ira->codegen, target_val_ptr, instruction->base.source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, - get_pointer_to_type(ira->codegen, first_field->type_entry, - target_val_ptr->type->data.pointer.is_const)); - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut; - out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_union.payload; - return result; - } - - ZigType *result_type = get_pointer_to_type(ira->codegen, first_field->type_entry, - target_value_ptr->value->type->data.pointer.is_const); - return ir_build_union_field_ptr(ira, instruction->base.scope, instruction->base.source_node, target_value_ptr, first_field, - false, false, result_type); - } else if (target_type->id == ZigTypeIdErrorSet) { - // construct an error set from the prong values - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - ZigList error_list = {}; - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - for (size_t i = 0; i < instruction->prongs_len; i += 1) { - ErrorTableEntry *err = ir_resolve_error(ira, instruction->prongs_ptr[i]->child); - if (err == nullptr) - return ira->codegen->invalid_inst_gen; - error_list.append(err); - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&err->name)); - } - err_set_type->data.error_set.errors = error_list.items; - err_set_type->data.error_set.err_count = error_list.length; - buf_appendf(&err_set_type->name, "}"); - - - ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen, - err_set_type, - ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile, - ref_type->data.pointer.ptr_len, - ref_type->data.pointer.explicit_alignment, - ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, - ref_type->data.pointer.allow_zero); - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, - target_value_ptr, instruction->target_value_ptr->source_node, - new_target_value_ptr_type, instruction->base.source_node, false, false); - } else if (instruction->prongs_len > 1) { - return target_value_ptr; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -static Stage1AirInst *ir_analyze_instruction_switch_else_var(IrAnalyze *ira, - Stage1ZirInstSwitchElseVar *instruction) -{ - Stage1AirInst *target_value_ptr = instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ref_type = target_value_ptr->value->type; - assert(ref_type->id == ZigTypeIdPointer); - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - if (target_type->id == ZigTypeIdErrorSet) { - // make a new set that has the other cases removed - if (!resolve_inferred_error_set(ira->codegen, target_type, instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (type_is_global_error_set(target_type)) { - // the type of the else capture variable still has to be the global error set. - // once the runtime hint system is more sophisticated, we could add some hint information here. - return target_value_ptr; - } - // Make note of the errors handled by other cases - ErrorTableEntry **errors = heap::c_allocator.allocate(ira->codegen->errors_by_index.length); - // We may not have any case in the switch if this is a lone else - const size_t switch_cases = instruction->switch_br ? instruction->switch_br->case_count : 0; - for (size_t case_i = 0; case_i < switch_cases; case_i += 1) { - Stage1ZirInstSwitchBrCase *br_case = &instruction->switch_br->cases[case_i]; - Stage1AirInst *case_expr = br_case->value->child; - if (case_expr->value->type->id == ZigTypeIdErrorSet) { - ErrorTableEntry *err = ir_resolve_error(ira, case_expr); - if (err == nullptr) - return ira->codegen->invalid_inst_gen; - errors[err->value] = err; - } else if (case_expr->value->type->id == ZigTypeIdMetaType) { - ZigType *err_set_type = ir_resolve_type(ira, case_expr); - if (type_is_invalid(err_set_type)) - return ira->codegen->invalid_inst_gen; - populate_error_set_table(errors, err_set_type); - } else { - zig_unreachable(); - } - } - ZigList result_list = {}; - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - - // Look at all the errors in the type switched on and add them to the result_list - // if they are not handled by cases. - for (uint32_t i = 0; i < target_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = target_type->data.error_set.errors[i]; - ErrorTableEntry *existing_entry = errors[error_entry->value]; - if (existing_entry == nullptr) { - result_list.append(error_entry); - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name)); - } - } - heap::c_allocator.deallocate(errors, ira->codegen->errors_by_index.length); - - err_set_type->data.error_set.err_count = result_list.length; - err_set_type->data.error_set.errors = result_list.items; - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - - buf_appendf(&err_set_type->name, "}"); - - ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen, - err_set_type, - ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile, - ref_type->data.pointer.ptr_len, - ref_type->data.pointer.explicit_alignment, - ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, - ref_type->data.pointer.allow_zero); - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, - target_value_ptr, instruction->target_value_ptr->source_node, - new_target_value_ptr_type, instruction->base.source_node, false, false); - } - - return target_value_ptr; -} - -static Stage1AirInst *ir_analyze_instruction_import(IrAnalyze *ira, Stage1ZirInstImport *import_instruction) { - Error err; - - Stage1AirInst *name_value = import_instruction->name->child; - Buf *import_target_str = ir_resolve_str(ira, name_value); - if (!import_target_str) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = import_instruction->base.source_node; - ZigType *import = source_node->owner; - - ZigType *target_import; - Buf *import_target_path; - Buf full_path = BUF_INIT; - if ((err = analyze_import(ira->codegen, import, import_target_str, &target_import, - &import_target_path, &full_path))) - { - if (err == ErrorImportOutsidePkgPath) { - ir_add_error_node(ira, source_node, - buf_sprintf("import of file outside package path: '%s'", - buf_ptr(import_target_path))); - return ira->codegen->invalid_inst_gen; - } else if (err == ErrorFileNotFound) { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - } - - return ir_const_type(ira, import_instruction->base.scope, import_instruction->base.source_node, target_import); -} - -static Stage1AirInst *ir_analyze_instruction_ref(IrAnalyze *ira, Stage1ZirInstRef *ref_instruction) { - Stage1AirInst *value = ref_instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - bool is_const = false; - bool is_volatile = false; - - ZigValue *child_value = value->value; - if (child_value->special == ConstValSpecialStatic) { - is_const = true; - } - - return ir_get_ref(ira, ref_instruction->base.scope, ref_instruction->base.source_node, value, is_const, is_volatile); -} - -static Stage1AirInst *ir_analyze_union_init(IrAnalyze *ira, Scope *scope, AstNode *source_node, - AstNode *field_source_node, ZigType *union_type, Buf *field_name, Stage1AirInst *field_result_loc, - Stage1AirInst *result_loc) -{ - Error err; - assert(union_type->id == ZigTypeIdUnion); - - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *type_field = find_union_type_field(union_type, field_name); - if (type_field == nullptr) { - ir_add_error_node(ira, field_source_node, - buf_sprintf("no field named '%s' in union '%s'", - buf_ptr(field_name), buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (type_is_invalid(type_field->type_entry)) - return ira->codegen->invalid_inst_gen; - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (instr_is_comptime(field_result_loc) && - field_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - // nothing - } else { - result_loc->value->special = ConstValSpecialRuntime; - } - } - - bool is_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, union_type) == ReqCompTimeYes; - - Stage1AirInst *result = ir_get_deref(ira, scope, source_node, result_loc, nullptr); - if (is_comptime && !instr_is_comptime(result)) { - ir_add_error(ira, field_result_loc, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static Stage1AirInst *ir_analyze_container_init_fields(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *container_type, size_t instr_field_count, Stage1ZirInstContainerInitFieldsField *fields, - Stage1AirInst *result_loc) -{ - Error err; - if (container_type->id == ZigTypeIdUnion) { - if (instr_field_count != 1) { - ir_add_error_node(ira, source_node, - buf_sprintf("union initialization expects exactly one field")); - return ira->codegen->invalid_inst_gen; - } - Stage1ZirInstContainerInitFieldsField *field = &fields[0]; - Stage1AirInst *field_result_loc = field->result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_union_init(ira, scope, source_node, field->source_node, container_type, field->name, - field_result_loc, result_loc); - } - if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("type '%s' does not support struct initialization syntax", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (container_type->data.structure.resolve_status == ResolveStatusBeingInferred) { - // We're now done inferring the type. - container_type->data.structure.resolve_status = ResolveStatusUnstarted; - } - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t actual_field_count = container_type->data.structure.src_field_count; - - Stage1AirInst *first_non_const_instruction = nullptr; - - AstNode **field_assign_nodes = heap::c_allocator.allocate(actual_field_count); - ZigList const_ptrs = {}; - - bool is_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; - - - // Here we iterate over the fields that have been initialized, and emit - // compile errors for missing fields and duplicate fields. - // It is only now that we find out whether the struct initialization can be a comptime - // value, but we have already emitted runtime instructions for the fields that - // were initialized with runtime values, and have omitted instructions that would have - // initialized fields with comptime values. - // So now we must clean up this situation. If it turns out the struct initialization can - // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst. - // Otherwise, we must emit instructions to runtime-initialize the fields that have - // comptime-known values. - - for (size_t i = 0; i < instr_field_count; i += 1) { - Stage1ZirInstContainerInitFieldsField *field = &fields[i]; - - Stage1AirInst *field_result_loc = field->result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *type_field = find_struct_type_field(container_type, field->name); - if (!type_field) { - ir_add_error_node(ira, field->source_node, - buf_sprintf("no field named '%s' in struct '%s'", - buf_ptr(field->name), buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (type_is_invalid(type_field->type_entry)) - return ira->codegen->invalid_inst_gen; - - size_t field_index = type_field->src_index; - AstNode *existing_assign_node = field_assign_nodes[field_index]; - if (existing_assign_node) { - ErrorMsg *msg = ir_add_error_node(ira, field->source_node, buf_sprintf("duplicate field")); - add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); - return ira->codegen->invalid_inst_gen; - } - field_assign_nodes[field_index] = field->source_node; - - if (instr_is_comptime(field_result_loc) && - field_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - const_ptrs.append(field_result_loc); - } else { - first_non_const_instruction = field_result_loc; - } - } - - bool any_missing = false; - for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i] != nullptr) continue; - - // look for a default field value - TypeStructField *field = container_type->data.structure.fields[i]; - memoize_field_init_val(ira->codegen, container_type, field); - if (field->init_val == nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("missing field: '%s'", buf_ptr(field->name))); - any_missing = true; - continue; - } - if (type_is_invalid(field->init_val->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *runtime_inst = ir_const(ira, scope, source_node, field->init_val->type); - copy_const_val(ira->codegen, runtime_inst->value, field->init_val); - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, result_loc, - container_type, true); - ir_analyze_store_ptr(ira, scope, source_node, field_ptr, runtime_inst, false); - if (instr_is_comptime(field_ptr) && field_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - const_ptrs.append(field_ptr); - } else { - first_non_const_instruction = result_loc; - } - } - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - if (any_missing) - return ira->codegen->invalid_inst_gen; - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (const_ptrs.length != actual_field_count) { - result_loc->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *field_result_loc = const_ptrs.at(i); - Stage1AirInst *deref = ir_get_deref(ira, field_result_loc->scope, - field_result_loc->source_node, field_result_loc, nullptr); - field_result_loc->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, field_result_loc->scope, field_result_loc->source_node, - field_result_loc, deref, false); - } - } - } - - const_ptrs.deinit(); - Stage1AirInst *result = ir_get_deref(ira, scope, source_node, result_loc, nullptr); - - if (is_comptime && !instr_is_comptime(result)) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira, - Stage1ZirInstContainerInitList *instruction) -{ - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *container_type = result_loc->value->type->data.pointer.child_type; - size_t elem_count = instruction->item_count; - - if (is_slice(container_type)) { - ir_add_error_node(ira, instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (container_type->id == ZigTypeIdVoid) { - if (elem_count != 0) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); - return ira->codegen->invalid_inst_gen; - } - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - if (container_type->id == ZigTypeIdStruct && elem_count == 0) { - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - return ir_analyze_container_init_fields(ira, instruction->base.scope, instruction->base.source_node, container_type, 0, nullptr, result_loc); - } - - if (container_type->id == ZigTypeIdArray) { - ZigType *child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, nullptr); - - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (container_type->id == ZigTypeIdStruct && - container_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - // We're now done inferring the type. - container_type->data.structure.resolve_status = ResolveStatusUnstarted; - } else if (container_type->id == ZigTypeIdVector || is_tuple(container_type)) { - // OK - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - switch (type_has_one_possible_value(ira->codegen, container_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, - get_the_one_possible_value(ira->codegen, container_type)); - case OnePossibleValueNo: - break; - } - - bool is_comptime; - switch (type_requires_comptime(ira->codegen, container_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - is_comptime = ir_should_inline(ira->zir, instruction->base.scope); - break; - case ReqCompTimeYes: - is_comptime = true; - break; - } - - Stage1AirInst *first_non_const_instruction = nullptr; - - // The Result Location Mechanism has already emitted runtime instructions to - // initialize runtime elements and has omitted instructions for the comptime - // elements. However it is only now that we find out whether the array initialization - // can be a comptime value. So we must clean up the situation. If it turns out - // array initialization can be a comptime value, overwrite ConstPtrMutInfer with - // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the - // elements that have comptime-known values. - ZigList const_ptrs = {}; - - for (size_t i = 0; i < elem_count; i += 1) { - Stage1AirInst *elem_result_loc = instruction->elem_result_loc_list[i]->child; - if (type_is_invalid(elem_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - assert(elem_result_loc->value->type->id == ZigTypeIdPointer); - - if (instr_is_comptime(elem_result_loc) && - elem_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - const_ptrs.append(elem_result_loc); - } else { - first_non_const_instruction = elem_result_loc; - } - } - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (const_ptrs.length != elem_count) { - result_loc->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - elem_result_loc->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, elem_result_loc->scope, elem_result_loc->source_node, - elem_result_loc, deref, false); - } - } - } - - const_ptrs.deinit(); - - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - result_loc, nullptr); - // If the result is a tuple, we are allowed to return a struct that uses ConstValSpecialRuntime fields at comptime. - if (instr_is_comptime(result) || is_tuple(container_type)) - return result; - - if (is_comptime) { - ir_add_error(ira, first_non_const_instruction, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_elem_type = result_loc->value->type->data.pointer.child_type; - if (is_slice(result_elem_type)) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("runtime-initialized array cannot be casted to slice type '%s'", - buf_ptr(&result_elem_type->name))); - add_error_note(ira->codegen, msg, first_non_const_instruction->source_node, - buf_sprintf("this value is not comptime-known")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, - Stage1ZirInstContainerInitFields *instruction) -{ - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *container_type = result_loc->value->type->data.pointer.child_type; - - return ir_analyze_container_init_fields(ira, instruction->base.scope, instruction->base.source_node, container_type, - instruction->field_count, instruction->fields, result_loc); -} - -static Stage1AirInst *ir_analyze_instruction_compile_err(IrAnalyze *ira, Stage1ZirInstCompileErr *instruction) { - Stage1AirInst *msg_value = instruction->msg->child; - Buf *msg_buf = ir_resolve_str(ira, msg_value); - if (!msg_buf) - return ira->codegen->invalid_inst_gen; - - ir_add_error_node(ira, instruction->base.source_node, msg_buf); - - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_instruction_compile_log(IrAnalyze *ira, Stage1ZirInstCompileLog *instruction) { - Buf buf = BUF_INIT; - fprintf(stderr, "| "); - for (size_t i = 0; i < instruction->msg_count; i += 1) { - Stage1AirInst *msg = instruction->msg_list[i]->child; - if (type_is_invalid(msg->value->type)) - return ira->codegen->invalid_inst_gen; - buf_resize(&buf, 0); - if (msg->value->special == ConstValSpecialLazy) { - // Resolve any lazy value that's passed, we need its value - if (ir_resolve_lazy(ira->codegen, msg->source_node, msg->value)) - return ira->codegen->invalid_inst_gen; - } - render_const_value(ira->codegen, &buf, msg->value); - const char *comma_str = (i != 0) ? ", " : ""; - fprintf(stderr, "%s%s", comma_str, buf_ptr(&buf)); - } - fprintf(stderr, "\n"); - - auto *expr = &instruction->base.source_node->data.fn_call_expr; - if (!expr->seen) { - // Here we bypass higher level functions such as ir_add_error because we do not want - // invalidate_exec to be called. - add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement")); - } - expr->seen = true; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_err_name(IrAnalyze *ira, Stage1ZirInstErrName *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - ErrorTableEntry *err = casted_value->value->data.x_err_set; - if (!err->cached_error_name_val) { - err->cached_error_name_val = create_sentineled_str_lit( - ira->codegen, &err->name, - ira->codegen->intern.for_zero_byte()); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = err->cached_error_name_val; - return result; - } - - ira->codegen->generate_error_name_table = true; - - ZigType *u8_ptr_type = get_pointer_to_type_extra2(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, ira->codegen->intern.for_zero_byte()); - ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); - return ir_build_err_name_gen(ira, instruction->base.scope, instruction->base.source_node, value, str_type); -} - -static Stage1AirInst *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, Stage1ZirInstTagName *instruction) { - Error err; - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *target_type = target->value->type; - - if (target_type->id == ZigTypeIdEnumLiteral) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - Buf *field_name = target->value->data.x_enum_literal; - result->value = create_sentineled_str_lit( - ira->codegen, field_name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - if (target_type->id == ZigTypeIdUnion) { - target = ir_analyze_union_tag(ira, instruction->base.scope, instruction->base.source_node, target); - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - target_type = target->value->type; - } - - if (target_type->id != ZigTypeIdEnum) { - ir_add_error(ira, target, - buf_sprintf("expected enum tag, found '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (can_fold_enum_type(target_type)) { - TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = create_sentineled_str_lit( - ira->codegen, only_field->name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - if (instr_is_comptime(target)) { - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - TypeEnumField *field = find_enum_field_by_tag(target_type, &target->value->data.x_bigint); - if (field == nullptr) { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &target->value->data.x_bigint, 10); - - ir_add_error(ira, target, - buf_sprintf("no tag by value %s", buf_ptr(int_buf))); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = create_sentineled_str_lit( - ira->codegen, field->name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra2( - ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, ira->codegen->intern.for_zero_byte()); - ZigType *result_type = get_slice_type(ira->codegen, u8_ptr_type); - return ir_build_tag_name_gen(ira, instruction->base.scope, instruction->base.source_node, target, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, - Stage1ZirInstFieldParentPtr *instruction) -{ - Error err; - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_name_value = instruction->field_name->child; - Buf *field_name = ir_resolve_str(ira, field_name_value); - if (!field_name) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_ptr = instruction->field_ptr->child; - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - TypeStructField *field = find_struct_type_field(container_type, field_name); - if (field == nullptr) { - ir_add_error(ira, field_name_value, - buf_sprintf("struct '%s' has no field '%s'", - buf_ptr(&container_type->name), buf_ptr(field_name))); - return ira->codegen->invalid_inst_gen; - } - - if (field_ptr->value->type->id != ZigTypeIdPointer) { - ir_add_error(ira, field_ptr, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool is_packed = (container_type->data.structure.layout == ContainerLayoutPacked); - uint32_t field_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); - uint32_t parent_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, container_type); - - ZigType *field_ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, - field_ptr->value->type->data.pointer.is_const, - field_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - field_ptr_align, 0, 0, false); - Stage1AirInst *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type); - if (type_is_invalid(casted_field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, container_type, - casted_field_ptr->value->type->data.pointer.is_const, - casted_field_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - parent_ptr_align, 0, 0, false); - - if (instr_is_comptime(casted_field_ptr)) { - ZigValue *field_ptr_val = ir_resolve_const(ira, casted_field_ptr, UndefBad); - if (!field_ptr_val) - return ira->codegen->invalid_inst_gen; - - if (field_ptr_val->data.x_ptr.special != ConstPtrSpecialBaseStruct) { - ir_add_error(ira, field_ptr, buf_sprintf("pointer value not based on parent struct")); - return ira->codegen->invalid_inst_gen; - } - - size_t ptr_field_index = field_ptr_val->data.x_ptr.data.base_struct.field_index; - if (ptr_field_index != field->src_index) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("field '%s' has index %" ZIG_PRI_usize " but pointer value is index %" ZIG_PRI_usize " of struct '%s'", - buf_ptr(field->name), field->src_index, - ptr_field_index, buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = field_ptr_val->data.x_ptr.data.base_struct.struct_val; - out_val->data.x_ptr.mut = field_ptr_val->data.x_ptr.mut; - return result; - } - - return ir_build_field_parent_ptr_gen(ira, instruction->base.scope, instruction->base.source_node, casted_field_ptr, field, result_type); -} - -static TypeStructField *validate_host_int_byte_offset(IrAnalyze *ira, - Stage1AirInst *type_value, - Stage1AirInst *field_name_value, - size_t *byte_offset) -{ - ZigType *container_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(container_type)) - return nullptr; - - Error err; - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return nullptr; - - Buf *field_name = ir_resolve_str(ira, field_name_value); - if (!field_name) - return nullptr; - - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return nullptr; - } - - TypeStructField *field = find_struct_type_field(container_type, field_name); - if (field == nullptr) { - ir_add_error(ira, field_name_value, - buf_sprintf("struct '%s' has no field '%s'", - buf_ptr(&container_type->name), buf_ptr(field_name))); - return nullptr; - } - - if (!type_has_bits(ira->codegen, field->type_entry)) { - ir_add_error(ira, field_name_value, - buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", - buf_ptr(field_name), buf_ptr(&container_type->name))); - return nullptr; - } - - *byte_offset = field->offset; - return field; -} - -static Stage1AirInst *ir_analyze_instruction_offset_of(IrAnalyze *ira, Stage1ZirInstOffsetOf *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_name_value = instruction->field_name->child; - size_t host_int_byte_offset = 0; - TypeStructField *field = nullptr; - if (!(field = validate_host_int_byte_offset(ira, type_value, field_name_value, &host_int_byte_offset))) - return ira->codegen->invalid_inst_gen; - - size_t byte_offset = host_int_byte_offset + (field->bit_offset_in_host / 8); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, byte_offset); -} - -static Stage1AirInst *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, Stage1ZirInstBitOffsetOf *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_name_value = instruction->field_name->child; - size_t host_int_byte_offset = 0; - TypeStructField *field = nullptr; - if (!(field = validate_host_int_byte_offset(ira, type_value, field_name_value, &host_int_byte_offset))) - return ira->codegen->invalid_inst_gen; - - size_t bit_offset = host_int_byte_offset * 8 + field->bit_offset_in_host; - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, bit_offset); -} - -static void ensure_field_index(ZigType *type, const char *field_name, size_t index) { - Buf *field_name_buf; - - assert(type != nullptr && !type_is_invalid(type)); - field_name_buf = buf_create_from_str(field_name); - TypeStructField *field = find_struct_type_field(type, field_name_buf); - buf_deinit(field_name_buf); - - if (field == nullptr || field->src_index != index) - zig_panic("reference to unknown field %s", field_name); -} - -static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { - Error err; - ZigType *type_info_type = get_builtin_type(ira->codegen, "Type"); - assert(type_info_type->id == ZigTypeIdUnion); - if ((err = type_resolve(ira->codegen, type_info_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - - if (type_name == nullptr && root == nullptr) - return type_info_type; - else if (type_name == nullptr) - return root; - - ZigType *root_type = (root == nullptr) ? type_info_type : root; - - ScopeDecls *type_info_scope = get_container_scope(root_type); - assert(type_info_scope != nullptr); - - Buf field_name = BUF_INIT; - buf_init_from_str(&field_name, type_name); - auto entry = type_info_scope->decl_table.get(&field_name); - buf_deinit(&field_name); - - TldVar *tld = (TldVar *)entry; - assert(tld->base.id == TldIdVar); - - ZigVar *var = tld->var; - - assert(var->const_value->type->id == ZigTypeIdMetaType); - - return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, nullptr, var->const_value); -} - -static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigValue *out_val, - ScopeDecls *decls_scope, bool resolve_types) -{ - Error err; - ZigType *type_info_declaration_type = ir_type_info_get_type(ira, "Declaration", nullptr); - if ((err = type_resolve(ira->codegen, type_info_declaration_type, ResolveStatusSizeKnown))) - return err; - - ensure_field_index(type_info_declaration_type, "name", 0); - ensure_field_index(type_info_declaration_type, "is_pub", 1); - - if (!resolve_types) { - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, type_info_declaration_type, - false, false, PtrLenUnknown, 0, 0, 0, false); - - out_val->special = ConstValSpecialLazy; - out_val->type = get_slice_type(ira->codegen, ptr_type); - - LazyValueTypeInfoDecls *lazy_type_info_decls = heap::c_allocator.create(); - lazy_type_info_decls->ira = ira; ira_ref(ira); - out_val->data.x_lazy = &lazy_type_info_decls->base; - lazy_type_info_decls->base.id = LazyValueIdTypeInfoDecls; - - lazy_type_info_decls->source_node = source_node; - lazy_type_info_decls->decls_scope = decls_scope; - - return ErrorNone; - } - - resolve_container_usingnamespace_decls(ira->codegen, decls_scope); - - // Loop through our declarations once to figure out how many declarations - // we will generate info for. - int declaration_count = 0; - auto decl_it = decls_scope->decl_table.entry_iterator(); - decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; - while ((curr_entry = decl_it.next()) != nullptr) { - // Skip comptime blocks and test functions. - if (curr_entry->value->id == TldIdCompTime) - continue; - - if (curr_entry->value->id == TldIdFn && - curr_entry->value->source_node->type == NodeTypeTestDecl) - { - continue; - } - - if (curr_entry->value->resolution == TldResolutionInvalid) - return ErrorSemanticAnalyzeFail; - - declaration_count += 1; - } - - ZigValue *declaration_array = ira->codegen->pass1_arena->create(); - declaration_array->special = ConstValSpecialStatic; - declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, nullptr); - declaration_array->data.x_array.special = ConstArraySpecialNone; - declaration_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(declaration_count); - init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false, nullptr); - - // Loop through the declarations and generate info. - decl_it = decls_scope->decl_table.entry_iterator(); - curr_entry = nullptr; - int declaration_index = 0; - while ((curr_entry = decl_it.next()) != nullptr) { - // Skip comptime blocks and test functions. - if (curr_entry->value->id == TldIdCompTime) { - continue; - } - if (curr_entry->value->id == TldIdFn && - curr_entry->value->source_node->type == NodeTypeTestDecl) - { - continue; - } - - ZigValue *declaration_val = &declaration_array->data.x_array.data.s_none.elements[declaration_index]; - - declaration_val->special = ConstValSpecialStatic; - declaration_val->type = type_info_declaration_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); - ZigValue *name = create_const_str_lit(ira->codegen, curr_entry->key)->data.x_ptr.data.ref.pointee; - init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(curr_entry->key), true, nullptr); - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = ira->codegen->builtin_types.entry_bool; - inner_fields[1]->data.x_bool = curr_entry->value->visib_mod == VisibModPub; - - declaration_val->data.x_struct.fields = inner_fields; - declaration_index += 1; - } - - assert(declaration_index == declaration_count); - return ErrorNone; -} - -static BuiltinPtrSize ptr_len_to_size_enum_index(PtrLen ptr_len) { - switch (ptr_len) { - case PtrLenSingle: - return BuiltinPtrSizeOne; - case PtrLenUnknown: - return BuiltinPtrSizeMany; - case PtrLenC: - return BuiltinPtrSizeC; - } - zig_unreachable(); -} - -static PtrLen size_enum_index_to_ptr_len(BuiltinPtrSize size_enum_index) { - switch (size_enum_index) { - case BuiltinPtrSizeOne: - return PtrLenSingle; - case BuiltinPtrSizeMany: - case BuiltinPtrSizeSlice: - return PtrLenUnknown; - case BuiltinPtrSizeC: - return PtrLenC; - } - zig_unreachable(); -} - -static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ptr_type_entry) { - CodeGen *g = ira->codegen; - ZigType *attrs_type; - BuiltinPtrSize size_enum_index; - if (is_slice(ptr_type_entry)) { - TypeStructField *ptr_field = ptr_type_entry->data.structure.fields[slice_ptr_index]; - attrs_type = resolve_struct_field_type(g, ptr_field); - size_enum_index = BuiltinPtrSizeSlice; - } else if (ptr_type_entry->id == ZigTypeIdPointer) { - attrs_type = ptr_type_entry; - size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); - } else { - zig_unreachable(); - } - - ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); - assertNoError(type_resolve(g, type_info_pointer_type, ResolveStatusSizeKnown)); - - ZigValue *result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = type_info_pointer_type; - - ZigValue **fields = alloc_const_vals_ptrs(g, 8); - result->data.x_struct.fields = fields; - - // size: Size - ensure_field_index(result->type, "size", 0); - ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); - assertNoError(type_resolve(g, type_info_pointer_size_type, ResolveStatusSizeKnown)); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = type_info_pointer_size_type; - bigint_init_unsigned(&fields[0]->data.x_enum_tag, size_enum_index); - - // is_const: bool - ensure_field_index(result->type, "is_const", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_bool; - fields[1]->data.x_bool = attrs_type->data.pointer.is_const; - // is_volatile: bool - ensure_field_index(result->type, "is_volatile", 2); - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_bool; - fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile; - // alignment: comptime_int - ensure_field_index(result->type, "alignment", 3); - fields[3]->type = g->builtin_types.entry_num_lit_int; - if (attrs_type->data.pointer.explicit_alignment != 0) { - fields[3]->special = ConstValSpecialStatic; - bigint_init_unsigned(&fields[3]->data.x_bigint, attrs_type->data.pointer.explicit_alignment); - } else { - LazyValueAlignOf *lazy_align_of = heap::c_allocator.create(); - lazy_align_of->ira = ira; ira_ref(ira); - fields[3]->special = ConstValSpecialLazy; - fields[3]->data.x_lazy = &lazy_align_of->base; - lazy_align_of->base.id = LazyValueIdAlignOf; - lazy_align_of->target_type = ir_const_type(ira, scope, source_node, attrs_type->data.pointer.child_type); - } - // address_space: AddressSpace, - ensure_field_index(result->type, "address_space", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = get_builtin_type(g, "AddressSpace"); - bigint_init_unsigned(&fields[4]->data.x_enum_tag, AddressSpaceGeneric); - // child: type - ensure_field_index(result->type, "child", 5); - fields[5]->special = ConstValSpecialStatic; - fields[5]->type = g->builtin_types.entry_type; - fields[5]->data.x_type = attrs_type->data.pointer.child_type; - // is_allowzero: bool - ensure_field_index(result->type, "is_allowzero", 6); - fields[6]->special = ConstValSpecialStatic; - fields[6]->type = g->builtin_types.entry_bool; - fields[6]->data.x_bool = attrs_type->data.pointer.allow_zero; - // sentinel: ?*const anyopaque - ensure_field_index(result->type, "sentinel", 7); - fields[7]->special = ConstValSpecialStatic; - fields[7]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - ZigValue *ptr_to_sent = (attrs_type->data.pointer.sentinel == nullptr) ? nullptr : - create_const_ptr_ref(g, attrs_type->data.pointer.sentinel, true); - set_optional_payload(fields[7], ptr_to_sent); - - return result; -}; - -static void make_enum_field_val(IrAnalyze *ira, ZigValue *enum_field_val, TypeEnumField *enum_field, - ZigType *type_info_enum_field_type) -{ - enum_field_val->special = ConstValSpecialStatic; - enum_field_val->type = type_info_enum_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; - - ZigValue *name = create_const_str_lit(ira->codegen, enum_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(enum_field->name), true, nullptr); - - bigint_init_bigint(&inner_fields[1]->data.x_bigint, &enum_field->value); - - enum_field_val->data.x_struct.fields = inner_fields; -} - -static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *type_entry, - ZigValue **out) -{ - Error err; - assert(type_entry != nullptr); - assert(!type_is_invalid(type_entry)); - - CodeGen *g = ira->codegen; - - auto entry = g->type_info_cache.maybe_get(type_entry); - if (entry != nullptr) { - *out = entry->value; - return ErrorNone; - } - - ZigValue *result = nullptr; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - result = g->intern.for_void(); - break; - case ZigTypeIdInt: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Int", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // is_signed: Signedness - ensure_field_index(result->type, "signedness", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_builtin_type(g, "Signedness"); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, !type_entry->data.integral.is_signed); - // bits: u8 - ensure_field_index(result->type, "bits", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.integral.bit_count); - - break; - } - case ZigTypeIdFloat: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Float", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // bits: u8 - ensure_field_index(result->type, "bits", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.floating.bit_count); - - break; - } - case ZigTypeIdPointer: - { - result = create_ptr_like_type_info(ira, scope, source_node, type_entry); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - break; - } - case ZigTypeIdArray: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Array", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 3); - result->data.x_struct.fields = fields; - - // len: usize - ensure_field_index(result->type, "len", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.array.len); - // child: type - ensure_field_index(result->type, "child", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.array.child_type; - src_assert(type_entry->data.array.child_type != nullptr, source_node); - // sentinel: ?*const anyopaque - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - ZigValue *ptr_to_sent = (type_entry->data.array.sentinel == nullptr) ? nullptr : - create_const_ptr_ref(g, type_entry->data.array.sentinel, true); - set_optional_payload(fields[2], ptr_to_sent); - break; - } - case ZigTypeIdVector: { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Vector", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // len: usize - ensure_field_index(result->type, "len", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.vector.len); - // child: type - ensure_field_index(result->type, "child", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.vector.elem_type; - - break; - } - case ZigTypeIdOptional: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Optional", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // child: type - ensure_field_index(result->type, "child", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_type; - fields[0]->data.x_type = type_entry->data.maybe.child_type; - - break; - } - case ZigTypeIdAnyFrame: { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // child: ?type - ensure_field_index(result->type, "child", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_optional_type(g, g->builtin_types.entry_type); - fields[0]->data.x_optional = (type_entry->data.any_frame.result_type == nullptr) ? nullptr : - create_const_type(g, type_entry->data.any_frame.result_type); - break; - } - case ZigTypeIdEnum: - { - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Enum", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 5); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.enumeration.layout); - // tag_type: type - ensure_field_index(result->type, "tag_type", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.enumeration.tag_int_type; - // fields: []Type.EnumField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); - if ((err = type_resolve(g, type_info_enum_field_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - uint32_t enum_field_count = type_entry->data.enumeration.src_field_count; - - ZigValue *enum_field_array = g->pass1_arena->create(); - enum_field_array->special = ConstValSpecialStatic; - enum_field_array->type = get_array_type(g, type_info_enum_field_type, enum_field_count, nullptr); - enum_field_array->data.x_array.special = ConstArraySpecialNone; - enum_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(enum_field_count); - - init_const_slice(g, fields[2], enum_field_array, 0, enum_field_count, false, nullptr); - - for (uint32_t enum_field_index = 0; enum_field_index < enum_field_count; enum_field_index++) - { - TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; - ZigValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; - make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); - enum_field_val->parent.id = ConstParentIdArray; - enum_field_val->parent.data.p_array.array_val = enum_field_array; - enum_field_val->parent.data.p_array.elem_index = enum_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.enumeration.decls_scope, false))) - { - return err; - } - // is_exhaustive: bool - ensure_field_index(result->type, "is_exhaustive", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = g->builtin_types.entry_bool; - fields[4]->data.x_bool = !type_entry->data.enumeration.non_exhaustive; - - break; - } - case ZigTypeIdErrorSet: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "ErrorSet", nullptr); - - ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr); - if (!resolve_inferred_error_set(g, type_entry, source_node)) { - return ErrorSemanticAnalyzeFail; - } - if (type_is_global_error_set(type_entry)) { - result->data.x_optional = nullptr; - break; - } - if ((err = type_resolve(g, type_info_error_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - ZigValue *slice_val = g->pass1_arena->create(); - result->data.x_optional = slice_val; - - uint32_t error_count = type_entry->data.error_set.err_count; - ZigValue *error_array = g->pass1_arena->create(); - error_array->special = ConstValSpecialStatic; - error_array->type = get_array_type(g, type_info_error_type, error_count, nullptr); - error_array->data.x_array.special = ConstArraySpecialNone; - error_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(error_count); - - init_const_slice(g, slice_val, error_array, 0, error_count, false, nullptr); - for (uint32_t error_index = 0; error_index < error_count; error_index++) { - ErrorTableEntry *error = type_entry->data.error_set.errors[error_index]; - ZigValue *error_val = &error_array->data.x_array.data.s_none.elements[error_index]; - - error_val->special = ConstValSpecialStatic; - error_val->type = type_info_error_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 1); - - ZigValue *name = nullptr; - if (error->cached_error_name_val != nullptr) - name = error->cached_error_name_val; - if (name == nullptr) - name = create_const_str_lit(g, &error->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(&error->name), true, nullptr); - - error_val->data.x_struct.fields = inner_fields; - error_val->parent.id = ConstParentIdArray; - error_val->parent.data.p_array.array_val = error_array; - error_val->parent.data.p_array.elem_index = error_index; - } - - break; - } - case ZigTypeIdErrorUnion: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "ErrorUnion", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // error_set: type - ensure_field_index(result->type, "error_set", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_type; - fields[0]->data.x_type = type_entry->data.error_union.err_set_type; - - // payload: type - ensure_field_index(result->type, "payload", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.error_union.payload_type; - - break; - } - case ZigTypeIdUnion: - { - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Union", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 4); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.unionation.layout); - // tag_type: ?type - ensure_field_index(result->type, "tag_type", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = get_optional_type(g, g->builtin_types.entry_type); - - AstNode *union_decl_node = type_entry->data.unionation.decl_node; - if (union_decl_node->data.container_decl.auto_enum || - union_decl_node->data.container_decl.init_arg_expr != nullptr) - { - ZigValue *tag_type = g->pass1_arena->create(); - tag_type->special = ConstValSpecialStatic; - tag_type->type = g->builtin_types.entry_type; - tag_type->data.x_type = type_entry->data.unionation.tag_type; - fields[1]->data.x_optional = tag_type; - } else { - fields[1]->data.x_optional = nullptr; - } - // fields: []Type.UnionField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField", nullptr); - if ((err = type_resolve(g, type_info_union_field_type, ResolveStatusSizeKnown))) - zig_unreachable(); - uint32_t union_field_count = type_entry->data.unionation.src_field_count; - - ZigValue *union_field_array = g->pass1_arena->create(); - union_field_array->special = ConstValSpecialStatic; - union_field_array->type = get_array_type(g, type_info_union_field_type, union_field_count, nullptr); - union_field_array->data.x_array.special = ConstArraySpecialNone; - union_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(union_field_count); - - init_const_slice(g, fields[2], union_field_array, 0, union_field_count, false, nullptr); - - for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { - TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; - ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index]; - - union_field_val->special = ConstValSpecialStatic; - union_field_val->type = type_info_union_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 3); - // field_type: type - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_type; - inner_fields[1]->data.x_type = union_field->type_entry; - - // alignment: comptime_int - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align); - - ZigValue *name = create_const_str_lit(g, union_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(union_field->name), true, nullptr); - - union_field_val->data.x_struct.fields = inner_fields; - union_field_val->parent.id = ConstParentIdArray; - union_field_val->parent.data.p_array.array_val = union_field_array; - union_field_val->parent.data.p_array.elem_index = union_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.unionation.decls_scope, false))) - { - return err; - } - - break; - } - case ZigTypeIdStruct: - { - if (type_entry->data.structure.special == StructSpecialSlice) { - result = create_ptr_like_type_info(ira, scope, source_node, type_entry); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - break; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Struct", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 5); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout); - - // backing_integer: ?type - ensure_field_index(result->type, "backing_integer", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = get_optional_type(g, g->builtin_types.entry_type); - // This is always null in stage1, as stage1 does not support explicit backing integers - // for packed structs. - fields[1]->data.x_optional = nullptr; - - // fields: []Type.StructField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr); - if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - uint32_t struct_field_count = type_entry->data.structure.src_field_count; - - ZigValue *struct_field_array = g->pass1_arena->create(); - struct_field_array->special = ConstValSpecialStatic; - struct_field_array->type = get_array_type(g, type_info_struct_field_type, struct_field_count, nullptr); - struct_field_array->data.x_array.special = ConstArraySpecialNone; - struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(struct_field_count); - - init_const_slice(g, fields[2], struct_field_array, 0, struct_field_count, false, nullptr); - - for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { - TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index]; - ZigValue *struct_field_val = &struct_field_array->data.x_array.data.s_none.elements[struct_field_index]; - - struct_field_val->special = ConstValSpecialStatic; - struct_field_val->type = type_info_struct_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 5); - - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_type; - inner_fields[1]->data.x_type = struct_field->type_entry; - - // default_value: ?*const anyopaque - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - memoize_field_init_val(g, type_entry, struct_field); - if (struct_field->init_val != nullptr && - type_is_invalid(struct_field->init_val->type)) - { - return ErrorSemanticAnalyzeFail; - } - ZigValue *ptr_to_sent = (struct_field->init_val == nullptr) ? nullptr : - create_const_ptr_ref(g, struct_field->init_val, true); - set_optional_payload(inner_fields[2], ptr_to_sent); - - // is_comptime: bool - inner_fields[3]->special = ConstValSpecialStatic; - inner_fields[3]->type = g->builtin_types.entry_bool; - inner_fields[3]->data.x_bool = struct_field->is_comptime; - - // alignment: comptime_int - inner_fields[4]->special = ConstValSpecialStatic; - inner_fields[4]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align); - - ZigValue *name = create_const_str_lit(g, struct_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(struct_field->name), true, nullptr); - - struct_field_val->data.x_struct.fields = inner_fields; - struct_field_val->parent.id = ConstParentIdArray; - struct_field_val->parent.data.p_array.array_val = struct_field_array; - struct_field_val->parent.data.p_array.elem_index = struct_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.structure.decls_scope, false))) - { - return err; - } - - // is_tuple: bool - ensure_field_index(result->type, "is_tuple", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = g->builtin_types.entry_bool; - fields[4]->data.x_bool = is_tuple(type_entry); - - break; - } - case ZigTypeIdFn: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Fn", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 7); - result->data.x_struct.fields = fields; - - // calling_convention: Type.CallingConvention - ensure_field_index(result->type, "calling_convention", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_builtin_type(g, "CallingConvention"); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); - // alignment: comptime_int - ensure_field_index(result->type, "alignment", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(g, type_entry)); - // is_generic: bool - ensure_field_index(result->type, "is_generic", 2); - bool is_generic = type_entry->data.fn.is_generic; - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_bool; - fields[2]->data.x_bool = is_generic; - // is_varargs: bool - ensure_field_index(result->type, "is_var_args", 3); - bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; - fields[3]->special = ConstValSpecialStatic; - fields[3]->type = g->builtin_types.entry_bool; - fields[3]->data.x_bool = is_varargs; - // return_type: ?type - ensure_field_index(result->type, "return_type", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = get_optional_type(g, g->builtin_types.entry_type); - if (type_entry->data.fn.fn_type_id.return_type == nullptr) - fields[4]->data.x_optional = nullptr; - else { - ZigValue *return_type = g->pass1_arena->create(); - return_type->special = ConstValSpecialStatic; - return_type->type = g->builtin_types.entry_type; - return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; - fields[4]->data.x_optional = return_type; - } - // args: []Type.Fn.Param - ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "Param", result->type); - if ((err = type_resolve(g, type_info_fn_arg_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count; - - ZigValue *fn_arg_array = g->pass1_arena->create(); - fn_arg_array->special = ConstValSpecialStatic; - fn_arg_array->type = get_array_type(g, type_info_fn_arg_type, fn_arg_count, nullptr); - fn_arg_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(fn_arg_count); - - init_const_slice(g, fields[5], fn_arg_array, 0, fn_arg_count, false, nullptr); - - for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { - FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; - ZigValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index]; - - fn_arg_val->special = ConstValSpecialStatic; - fn_arg_val->type = type_info_fn_arg_type; - - bool arg_is_generic = fn_param_info->type == nullptr; - if (arg_is_generic) assert(is_generic); - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 3); - inner_fields[0]->special = ConstValSpecialStatic; - inner_fields[0]->type = g->builtin_types.entry_bool; - inner_fields[0]->data.x_bool = arg_is_generic; - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_bool; - inner_fields[1]->data.x_bool = fn_param_info->is_noalias; - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = get_optional_type(g, g->builtin_types.entry_type); - - if (arg_is_generic) - inner_fields[2]->data.x_optional = nullptr; - else { - ZigValue *arg_type = g->pass1_arena->create(); - arg_type->special = ConstValSpecialStatic; - arg_type->type = g->builtin_types.entry_type; - arg_type->data.x_type = fn_param_info->type; - inner_fields[2]->data.x_optional = arg_type; - } - - fn_arg_val->data.x_struct.fields = inner_fields; - fn_arg_val->parent.id = ConstParentIdArray; - fn_arg_val->parent.data.p_array.array_val = fn_arg_array; - fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; - } - - break; - } - case ZigTypeIdBoundFn: - { - ZigType *fn_type = type_entry->data.bound_fn.fn_type; - assert(fn_type->id == ZigTypeIdFn); - if ((err = ir_make_type_info_value(ira, scope, source_node, fn_type, &result))) - return err; - - break; - } - case ZigTypeIdOpaque: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Opaque", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 0); - if ((err = ir_make_type_info_decls(ira, source_node, fields[0], - type_entry->data.opaque.decls_scope, false))) - { - return err; - } - - break; - } - case ZigTypeIdFnFrame: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Frame", nullptr); - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - ZigFn *fn = type_entry->data.frame.fn; - // function: ?*const anyopaque - ensure_field_index(result->type, "function", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_pointer_to_type(g, g->builtin_types.entry_anyopaque, true); - fields[0]->data.x_ptr.special = ConstPtrSpecialFunction; - fields[0]->data.x_ptr.data.fn.fn_entry = fn; - break; - } - } - - assert(result != nullptr); - g->type_info_cache.put(type_entry, result); - *out = result; - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_type_info(IrAnalyze *ira, Stage1ZirInstTypeInfo *instruction) { - Error err; - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr); - - ZigValue *payload; - if ((err = ir_make_type_info_value(ira, instruction->base.scope, instruction->base.source_node, type_entry, &payload))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - ZigValue *out_val = result->value; - bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry)); - out_val->data.x_union.payload = payload; - - if (payload != nullptr) { - payload->parent.id = ConstParentIdUnion; - payload->parent.data.p_union.union_val = out_val; - } - - return result; -} - -static ZigValue *get_const_field(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index) -{ - Error err; - ensure_field_index(struct_value->type, name, field_index); - TypeStructField *field = struct_value->type->data.structure.fields[field_index]; - ZigValue *val = field->is_comptime ? field->init_val : - struct_value->data.x_struct.fields[field_index]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, val, UndefBad))) - return nullptr; - return val; -} - -static Error get_const_field_sentinel(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *struct_value, const char *name, size_t field_index, ZigType *elem_type, - ZigValue **result) -{ - ZigValue *field_val = get_const_field(ira, source_node, struct_value, name, field_index); - if (field_val == nullptr) - return ErrorSemanticAnalyzeFail; - - // type of `field_val` is `?*const anyopaque`. - if (field_val->data.x_ptr.special == ConstPtrSpecialNull) { - *result = nullptr; - return ErrorNone; - } - - ZigValue *pointee = const_ptr_pointee_unchecked_no_isf(ira->codegen, field_val); - if (pointee == nullptr) - return ErrorSemanticAnalyzeFail; - - *result = pointee; - return ErrorNone; -} - -static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, bool *out) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ErrorSemanticAnalyzeFail; - assert(value->type == ira->codegen->builtin_types.entry_bool); - *out = value->data.x_bool; - return ErrorNone; -} - -static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return nullptr; - assert(value->type == ira->codegen->builtin_types.entry_num_lit_int); - return &value->data.x_bigint; -} - -static ZigType *get_const_field_meta_type(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type == ira->codegen->builtin_types.entry_type); - return value->data.x_type; -} - -static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *source_node, - ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type->id == ZigTypeIdOptional); - assert(value->type->data.maybe.child_type == ira->codegen->builtin_types.entry_type); - if (value->data.x_optional == nullptr) - return nullptr; - return value->data.x_optional->data.x_type; -} - -static Error get_const_field_buf(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, Buf *out) -{ - ZigValue *slice = get_const_field(ira, source_node, struct_value, name, field_index); - ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; - ZigValue *len = slice->data.x_struct.fields[slice_len_index]; - assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; - assert(arr->special == ConstValSpecialStatic); - - const size_t start_value = ptr->data.x_ptr.data.base_array.elem_index; - const size_t len_value = bigint_as_usize(&len->data.x_bigint); - - switch (arr->data.x_array.special) { - case ConstArraySpecialUndef: - return ErrorSemanticAnalyzeFail; - case ConstArraySpecialNone: { - assert(start_value <= arr->type->data.array.len); - assert(start_value + len_value <= arr->type->data.array.len); - buf_resize(out, 0); - for (size_t j = 0; j < len_value; j++) { - ZigValue *ch_val = &arr->data.x_array.data.s_none.elements[start_value + j]; - unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); - buf_append_char(out, ch); - } - break; - } - case ConstArraySpecialBuf: - assert(start_value <= buf_len(arr->data.x_array.data.s_buf)); - assert(start_value + len_value <= buf_len(arr->data.x_array.data.s_buf)); - buf_init_from_mem(out, buf_ptr(arr->data.x_array.data.s_buf) + start_value, len_value); - break; - } - return ErrorNone; -} - -static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigTypeId tagTypeId, ZigValue *payload) { - Error err; - switch (tagTypeId) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return ira->codegen->builtin_types.entry_type; - case ZigTypeIdVoid: - return ira->codegen->builtin_types.entry_void; - case ZigTypeIdBool: - return ira->codegen->builtin_types.entry_bool; - case ZigTypeIdUnreachable: - return ira->codegen->builtin_types.entry_unreachable; - case ZigTypeIdComptimeFloat: - return ira->codegen->builtin_types.entry_num_lit_float; - case ZigTypeIdComptimeInt: - return ira->codegen->builtin_types.entry_num_lit_int; - case ZigTypeIdUndefined: - return ira->codegen->builtin_types.entry_undef; - case ZigTypeIdNull: - return ira->codegen->builtin_types.entry_null; - case ZigTypeIdEnumLiteral: - return ira->codegen->builtin_types.entry_enum_literal; - default: - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, payload, UndefBad))) - return ira->codegen->invalid_inst_gen->value->type; - } - switch (tagTypeId) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdEnumLiteral: - zig_unreachable(); - case ZigTypeIdInt: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Int", nullptr)); - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "bits", 1); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *value = get_const_field(ira, source_node, payload, "signedness", 0); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type == get_builtin_type(ira->codegen, "Signedness")); - bool is_signed = !bigint_as_u32(&value->data.x_enum_tag); - return get_int_type(ira->codegen, is_signed, bigint_as_u32(bi)); - } - case ZigTypeIdFloat: - { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Float", nullptr)); - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "bits", 0); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - uint32_t bits = bigint_as_u32(bi); - switch (bits) { - case 16: return ira->codegen->builtin_types.entry_f16; - case 32: return ira->codegen->builtin_types.entry_f32; - case 64: return ira->codegen->builtin_types.entry_f64; - case 80: return ira->codegen->builtin_types.entry_f80; - case 128: return ira->codegen->builtin_types.entry_f128; - } - ir_add_error_node(ira, source_node, buf_sprintf("%d-bit float unsupported", bits)); - return ira->codegen->invalid_inst_gen->value->type; - } - case ZigTypeIdPointer: - { - ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == type_info_pointer_type); - ZigValue *size_value = get_const_field(ira, source_node, payload, "size", 0); - if (size_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); - BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); - PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); - ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 5); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *sentinel; - if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 7, - elem_type, &sentinel))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - if (sentinel != nullptr && (size_enum_index == BuiltinPtrSizeOne || size_enum_index == BuiltinPtrSizeC)) { - ir_add_error_node(ira, source_node, - buf_sprintf("sentinels are only allowed on slices and unknown-length pointers")); - return ira->codegen->invalid_inst_gen->value->type; - } - - BigInt *alignment = get_const_field_lit_int(ira, source_node, payload, "alignment", 3); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - ZigValue *as_value = get_const_field(ira, source_node, payload, "address_space", 4); - if (as_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(as_value->special == ConstValSpecialStatic); - assert(as_value->type == get_builtin_type(ira->codegen, "AddressSpace")); - AddressSpace as = (AddressSpace)bigint_as_u32(&as_value->data.x_enum_tag); - if (as != AddressSpaceGeneric) { - ir_add_error_node(ira, source_node, buf_sprintf( - "address space '%s' not available in stage 1 compiler, must be .generic", - address_space_name(as))); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_const; - if ((err = get_const_field_bool(ira, source_node, payload, "is_const", 1, &is_const))) - return ira->codegen->invalid_inst_gen->value->type; - - bool is_volatile; - if ((err = get_const_field_bool(ira, source_node, payload, "is_volatile", 2, - &is_volatile))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_allowzero; - if ((err = get_const_field_bool(ira, source_node, payload, "is_allowzero", 6, - &is_allowzero))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, - elem_type, - is_const, - is_volatile, - ptr_len, - bigint_as_u32(alignment), - 0, // bit_offset_in_host - 0, // host_int_bytes - is_allowzero, - VECTOR_INDEX_NONE, nullptr, sentinel); - if (size_enum_index != BuiltinPtrSizeSlice) - return ptr_type; - return get_slice_type(ira->codegen, ptr_type); - } - case ZigTypeIdArray: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr)); - ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 1); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *sentinel; - if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 2, - elem_type, &sentinel))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "len", 0); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - return get_array_type(ira->codegen, elem_type, bigint_as_u64(bi), sentinel); - } - case ZigTypeIdOptional: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Optional", nullptr)); - ZigType *child_type = get_const_field_meta_type(ira, source_node, payload, "child", 0); - if (type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen->value->type; - return get_optional_type(ira->codegen, child_type); - } - case ZigTypeIdErrorUnion: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "ErrorUnion", nullptr)); - ZigType *err_set_type = get_const_field_meta_type(ira, source_node, payload, "error_set", 0); - if (type_is_invalid(err_set_type)) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *payload_type = get_const_field_meta_type(ira, source_node, payload, "payload", 1); - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen->value->type; - - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } - case ZigTypeIdOpaque: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr)); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 0); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Struct.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - Buf *bare_name = buf_alloc(); - Buf *full_name = get_anon_type_name(ira->codegen, - ira->zir, "opaque", scope, source_node, bare_name, nullptr); - return get_opaque_type(ira->codegen, - scope, source_node, buf_ptr(full_name), bare_name); - } - case ZigTypeIdVector: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Vector", nullptr)); - BigInt *len = get_const_field_lit_int(ira, source_node, payload, "len", 0); - if (len == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *child_type = get_const_field_meta_type(ira, source_node, payload, "child", 1); - if ((err = ir_validate_vector_elem_type(ira, source_node, child_type))) { - return ira->codegen->invalid_inst_gen->value->type; - } - return get_vector_type(ira->codegen, bigint_as_u32(len), child_type); - } - case ZigTypeIdAnyFrame: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "AnyFrame", nullptr)); - ZigType *child_type = get_const_field_meta_type_optional(ira, source_node, payload, "child", 0); - if (child_type != nullptr && type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen->value->type; - - return get_any_frame_type(ira->codegen, child_type); - } - case ZigTypeIdFnFrame: { - ir_add_error_node(ira, source_node, - buf_sprintf("use the @Frame builtin instead of @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - case ZigTypeIdErrorSet: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type->id == ZigTypeIdOptional); - ZigValue *slice = payload->data.x_optional; - if (slice == nullptr) - return ira->codegen->builtin_types.entry_global_error_set; - assert(slice->special == ConstValSpecialStatic); - assert(is_slice(slice->type)); - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - Buf bare_name = BUF_INIT; - buf_init_from_buf(&err_set_type->name, - get_anon_type_name(ira->codegen, ira->zir, "error", scope, source_node, &bare_name, nullptr)); - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; - assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);; - assert(ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; - assert(arr->special == ConstValSpecialStatic); - assert(arr->data.x_array.special == ConstArraySpecialNone); - ZigValue *len = slice->data.x_struct.fields[slice_len_index]; - size_t count = bigint_as_usize(&len->data.x_bigint); - err_set_type->data.error_set.err_count = count; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(count); - bool *already_set = heap::c_allocator.allocate(ira->codegen->errors_by_index.length + count); - for (size_t i = 0; i < count; i++) { - ZigValue *error = &arr->data.x_array.data.s_none.elements[i]; - assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); - ErrorTableEntry *err_entry = heap::c_allocator.create(); - err_entry->decl_node = source_node; - if ((err = get_const_field_buf(ira, source_node, error, "name", 0, &err_entry->name))) - return ira->codegen->invalid_inst_gen->value->type; - auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); - if (existing_entry) { - err_entry->value = existing_entry->value->value; - } else { - size_t error_value_count = ira->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); - err_entry->value = error_value_count; - ira->codegen->errors_by_index.append(err_entry); - } - if (already_set[err_entry->value]) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name))); - return ira->codegen->invalid_inst_gen->value->type; - } else { - already_set[err_entry->value] = true; - } - err_set_type->data.error_set.errors[i] = err_entry; - } - return err_set_type; - } - case ZigTypeIdStruct: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Struct", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "backing_integer", 1); - if (tag_type != nullptr) { - ir_add_error_node(ira, source_node, buf_create_from_str( - "the stage1 compiler does not support explicit backing integer types on packed structs")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Struct.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_tuple; - if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 4, &is_tuple))) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "struct", scope, source_node, &entry->name, nullptr)); - entry->data.structure.decl_node = source_node; - entry->data.structure.fields = alloc_type_struct_fields(fields_len); - entry->data.structure.fields_by_name.init(fields_len); - entry->data.structure.src_field_count = fields_len; - entry->data.structure.layout = layout; - entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; - entry->data.structure.created_by_at_type = true; - entry->data.structure.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "StructField", nullptr)); - TypeStructField *field = entry->data.structure.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - field->decl_node = source_node; - ZigValue *type_value = get_const_field(ira, source_node, field_value, "field_type", 1); - if (type_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->type_val = type_value; - field->type_entry = type_value->data.x_type; - if (entry->data.structure.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate struct field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - ZigValue *default_value = get_const_field(ira, source_node, field_value, "default_value", 2); - if (default_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - // type of `default_value` is `?*const anyopaque`. - if (default_value->data.x_ptr.special == ConstPtrSpecialNull) { - field->init_val = nullptr; - } else { - ZigValue *pointee = const_ptr_pointee_unchecked_no_isf(ira->codegen, default_value); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->init_val = pointee; - } - - if ((err = get_const_field_bool(ira, source_node, field_value, "is_comptime", 3, &field->is_comptime))) - return ira->codegen->invalid_inst_gen->value->type; - BigInt *alignment = get_const_field_lit_int(ira, source_node, field_value, "alignment", 4); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->align = bigint_as_u32(alignment); - } - - return entry; - } - case ZigTypeIdEnum: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Enum", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type(ira, source_node, payload, "tag_type", 1); - if (type_is_invalid(tag_type)) - return ira->codegen->invalid_inst_gen->value->type; - if (tag_type->id != ZigTypeIdInt) { - ir_add_error_node(ira, source_node, buf_sprintf( - "Type.Enum.tag_type must be an integer type, not '%s'", buf_ptr(&tag_type->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Enum.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - Error err; - bool is_exhaustive; - if ((err = get_const_field_bool(ira, source_node, payload, "is_exhaustive", 4, &is_exhaustive))) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *entry = new_type_table_entry(ZigTypeIdEnum); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "enum", scope, source_node, &entry->name, nullptr)); - entry->data.enumeration.decl_node = source_node; - entry->data.enumeration.tag_int_type = tag_type; - entry->data.enumeration.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - entry->data.enumeration.fields = heap::c_allocator.allocate(fields_len); - entry->data.enumeration.fields_by_name.init(fields_len); - entry->data.enumeration.src_field_count = fields_len; - entry->data.enumeration.layout = layout; - entry->data.enumeration.non_exhaustive = !is_exhaustive; - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "EnumField", nullptr)); - TypeEnumField *field = &entry->data.enumeration.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - field->decl_index = i; - field->decl_node = source_node; - if (entry->data.enumeration.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate enum field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - BigInt *field_int_value = get_const_field_lit_int(ira, source_node, field_value, "value", 1); - if (field_int_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->value = *field_int_value; - } - return entry; - } - case ZigTypeIdUnion: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "tag_type", 1); - if (tag_type != nullptr && type_is_invalid(tag_type)) { - return ira->codegen->invalid_inst_gen->value->type; - } - if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { - ir_add_error_node(ira, source_node, buf_sprintf( - "expected enum type, found '%s'", type_id_name(tag_type->id))); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Union.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdUnion); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "union", scope, source_node, &entry->name, nullptr)); - entry->data.unionation.decl_node = source_node; - entry->data.unionation.fields = heap::c_allocator.allocate(fields_len); - entry->data.unionation.fields_by_name.init(fields_len); - entry->data.unionation.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - entry->data.unionation.tag_type = tag_type; - entry->data.unionation.src_field_count = fields_len; - entry->data.unionation.layout = layout; - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr)); - TypeUnionField *field = &entry->data.unionation.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - field->decl_node = source_node; - ZigValue *type_value = get_const_field(ira, source_node, field_value, "field_type", 1); - if (type_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->type_val = type_value; - field->type_entry = type_value->data.x_type; - BigInt *alignment = get_const_field_lit_int(ira, source_node, field_value, "alignment", 2); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->align = bigint_as_u32(alignment); - } - return entry; - } - case ZigTypeIdFn: - case ZigTypeIdBoundFn: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr)); - - ZigValue *cc_value = get_const_field(ira, source_node, payload, "calling_convention", 0); - if (cc_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(cc_value->special == ConstValSpecialStatic); - assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention")); - CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag); - - BigInt *alignment = get_const_field_lit_int(ira, source_node, payload, "alignment", 1); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - Error err; - bool is_generic; - if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 2, &is_generic))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_generic) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.is_generic must be false for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_var_args; - if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 3, &is_var_args))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_var_args && cc != CallingConventionC) { - ir_add_error_node(ira, source_node, buf_sprintf("varargs functions must have C calling convention")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 4); - if (return_type == nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.return_type must be non-null for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 5); - if (args_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(args_value->special == ConstValSpecialStatic); - assert(is_slice(args_value->type)); - ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index]; - size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint); - - FnTypeId fn_type_id = {}; - fn_type_id.return_type = return_type; - fn_type_id.param_info = heap::c_allocator.allocate(args_len); - fn_type_id.param_count = args_len; - fn_type_id.next_param_index = args_len; - fn_type_id.is_var_args = is_var_args; - fn_type_id.cc = cc; - fn_type_id.alignment = bigint_as_u32(alignment); - - assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val; - assert(args_arr->special == ConstValSpecialStatic); - assert(args_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < args_len; i++) { - ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i]; - FnTypeParamInfo *info = &fn_type_id.param_info[i]; - Error err; - bool is_generic; - if ((err = get_const_field_bool(ira, source_node, arg_value, "is_generic", 0, &is_generic))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_generic) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.Param.is_generic must be false for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - if ((err = get_const_field_bool(ira, source_node, arg_value, "is_noalias", 1, &info->is_noalias))) - return ira->codegen->invalid_inst_gen->value->type; - ZigType *type = get_const_field_meta_type_optional( - ira, source_node, arg_value, "arg_type", 2); - if (type == nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.Param.arg_type must be non-null for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - info->type = type; - } - - ZigType *entry = get_fn_type(ira->codegen, &fn_type_id); - - switch (tagTypeId) { - case ZigTypeIdFn: - return entry; - case ZigTypeIdBoundFn: { - ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn); - bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name)); - bound_fn_entry->data.bound_fn.fn_type = entry; - return bound_fn_entry; - } - default: - zig_unreachable(); - } - } - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_type(IrAnalyze *ira, Stage1ZirInstType *instruction) { - Stage1AirInst *uncasted_type_info = instruction->type_info->child; - if (type_is_invalid(uncasted_type_info->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *type_info = ir_implicit_cast(ira, uncasted_type_info, ir_type_info_get_type(ira, nullptr, nullptr)); - if (type_is_invalid(type_info->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *type_info_val = ir_resolve_const(ira, type_info, UndefBad); - if (type_info_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigTypeId type_id_tag = type_id_at_index(bigint_as_usize(&type_info_val->data.x_union.tag)); - ZigType *type = type_info_to_type(ira, uncasted_type_info->scope, - uncasted_type_info->source_node, type_id_tag, type_info_val->data.x_union.payload); - if (type_is_invalid(type)) - return ira->codegen->invalid_inst_gen; - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, type); -} - -static Stage1AirInst *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, - Stage1ZirInstSetEvalBranchQuota *instruction) -{ - uint64_t new_quota; - if (!ir_resolve_unsigned(ira, instruction->new_quota->child, ira->codegen->builtin_types.entry_u32, &new_quota)) - return ira->codegen->invalid_inst_gen; - - if (new_quota > *ira->backward_branch_quota) { - *ira->backward_branch_quota = new_quota; - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_type_name(IrAnalyze *ira, Stage1ZirInstTypeName *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (!type_entry->cached_const_name_val) { - type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, type_bare_name(type_entry)); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, type_entry->cached_const_name_val); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_c_import(IrAnalyze *ira, Stage1ZirInstCImport *instruction) { - Error err; - AstNode *node = instruction->base.source_node; - assert(node->type == NodeTypeFnCallExpr); - AstNode *block_node = node->data.fn_call_expr.params.at(0); - - ScopeCImport *cimport_scope = create_cimport_scope(ira->codegen, node, instruction->base.scope); - - // Execute the C import block like an inline function - ZigType *void_type = ira->codegen->builtin_types.entry_void; - ZigValue *cimport_result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, void_type, &cimport_result, &result_ptr); - if ((err = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - if (type_is_invalid(cimport_result->type)) - return ira->codegen->invalid_inst_gen; - - ZigPackage *cur_scope_pkg = scope_package(instruction->base.scope); - RootStruct *root_struct = node->owner->data.structure.root_struct; - TokenLoc tok_loc = root_struct->token_locs[node->main_token]; - Buf *namespace_name = buf_sprintf("%s.cimport:%" PRIu32 ":%" PRIu32, - buf_ptr(&cur_scope_pkg->pkg_path), tok_loc.line + 1, tok_loc.column + 1); - - ZigPackage *cimport_pkg = new_anonymous_package(); - cimport_pkg->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package); - cimport_pkg->package_table.put(buf_create_from_str("std"), ira->codegen->std_package); - buf_init_from_buf(&cimport_pkg->pkg_path, namespace_name); - - const char *out_zig_path_ptr; - size_t out_zig_path_len; - Stage2ErrorMsg *errors_ptr; - size_t errors_len; - if ((err = stage2_cimport(&ira->codegen->stage1, - buf_ptr(&cimport_scope->buf), buf_len(&cimport_scope->buf), - &out_zig_path_ptr, &out_zig_path_len, - &errors_ptr, &errors_len))) - { - if (err != ErrorCCompileErrors) { - ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err))); - return ira->codegen->invalid_inst_gen; - } - - ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed")); - if (!ira->codegen->stage1.link_libc) { - add_error_note(ira->codegen, parent_err_msg, node, - buf_sprintf("libc headers not available; compilation does not link against libc")); - } - for (size_t i = 0; i < errors_len; i += 1) { - Stage2ErrorMsg *clang_err = &errors_ptr[i]; - // Clang can emit "too many errors, stopping now", in which case - // `source` and `filename_ptr` are null - if (clang_err->source && clang_err->filename_ptr) { - ErrorMsg *err_msg = err_msg_create_with_offset( - clang_err->filename_ptr ? - buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : - buf_alloc(), - clang_err->offset, clang_err->source, - buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len)); - err_msg_add_note(parent_err_msg, err_msg); - } - } - - return ira->codegen->invalid_inst_gen; - } - Buf *out_zig_path = buf_create_from_mem(out_zig_path_ptr, out_zig_path_len); - - Buf *import_code = buf_alloc(); - if ((err = file_fetch(ira->codegen, out_zig_path, import_code))) { - ir_add_error_node(ira, node, - buf_sprintf("unable to open '%s': %s", buf_ptr(out_zig_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - ZigType *child_import = add_source_file(ira->codegen, cimport_pkg, out_zig_path, - import_code, SourceKindCImport); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, child_import); -} - -static Stage1AirInst *ir_analyze_instruction_c_include(IrAnalyze *ira, Stage1ZirInstCInclude *instruction) { - Stage1AirInst *name_value = instruction->name->child; - if (type_is_invalid(name_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *include_name = ir_resolve_str(ira, name_value); - if (!include_name) - return ira->codegen->invalid_inst_gen; - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#include <%s>\n", buf_ptr(include_name)); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_c_define(IrAnalyze *ira, Stage1ZirInstCDefine *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *define_name = ir_resolve_str(ira, name); - if (!define_name) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *define_value = nullptr; - // The second parameter is either a string or void (equivalent to "") - if (value->value->type->id != ZigTypeIdVoid) { - define_value = ir_resolve_str(ira, value); - if (!define_value) - return ira->codegen->invalid_inst_gen; - } - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#define %s %s\n", buf_ptr(define_name), - define_value ? buf_ptr(define_value) : ""); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_c_undef(IrAnalyze *ira, Stage1ZirInstCUndef *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *undef_name = ir_resolve_str(ira, name); - if (!undef_name) - return ira->codegen->invalid_inst_gen; - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#undef %s\n", buf_ptr(undef_name)); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_embed_file(IrAnalyze *ira, Stage1ZirInstEmbedFile *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *rel_file_path = ir_resolve_str(ira, name); - if (!rel_file_path) - return ira->codegen->invalid_inst_gen; - - ZigType *import = get_scope_import(instruction->base.scope); - // figure out absolute path to resource - Buf source_dir_path = BUF_INIT; - os_path_dirname(import->data.structure.root_struct->path, &source_dir_path); - - Buf *resolve_paths[] = { - &source_dir_path, - rel_file_path, - }; - Buf *file_path = buf_alloc(); - *file_path = os_path_resolve(resolve_paths, 2); - - // load from file system into const expr - Buf *file_contents = buf_alloc(); - Error err; - if ((err = file_fetch(ira->codegen, file_path, file_contents))) { - if (err == ErrorFileNotFound) { - ir_add_error_node(ira, instruction->name->source_node, - buf_sprintf("unable to find '%s'", buf_ptr(file_path))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, instruction->name->source_node, - buf_sprintf("unable to open '%s': %s", buf_ptr(file_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - init_const_str_lit(ira->codegen, result->value, file_contents, true); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, Stage1ZirInstCmpxchg *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - if (operand_type->id == ZigTypeIdFloat) { - ir_add_error(ira, instruction->type_value->child, - buf_sprintf("expected bool, integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO let this be volatile - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast2(ira, instruction->ptr->scope, - instruction->ptr->source_node, ptr, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_value = instruction->cmp_value->child; - if (type_is_invalid(cmp_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *new_value = instruction->new_value->child; - if (type_is_invalid(new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *success_order_value = instruction->success_order_value->child; - if (type_is_invalid(success_order_value->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder success_order; - if (!ir_resolve_atomic_order(ira, success_order_value, &success_order)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *failure_order_value = instruction->failure_order_value->child; - if (type_is_invalid(failure_order_value->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder failure_order; - if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_cmp_value = ir_implicit_cast2(ira, instruction->cmp_value->scope, - instruction->cmp_value->source_node, cmp_value, operand_type); - if (type_is_invalid(casted_cmp_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_new_value = ir_implicit_cast2(ira, instruction->new_value->scope, - instruction->new_value->source_node, new_value, operand_type); - if (type_is_invalid(casted_new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (success_order < AtomicOrderMonotonic) { - ir_add_error(ira, success_order_value, - buf_sprintf("success atomic ordering must be Monotonic or stricter")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order < AtomicOrderMonotonic) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must be Monotonic or stricter")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order > success_order) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must be no stricter than success")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order == AtomicOrderRelease || failure_order == AtomicOrderAcqRel) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must not be Release or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = get_optional_type(ira->codegen, operand_type); - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - set_optional_value_to_null(result->value); - return result; - } - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar && - instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *stored_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (stored_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *expected_val = ir_resolve_const(ira, casted_cmp_value, UndefBad); - if (expected_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *new_val = ir_resolve_const(ira, casted_new_value, UndefBad); - if (new_val == nullptr) - return ira->codegen->invalid_inst_gen; - - bool eql = const_values_equal(ira->codegen, stored_val, expected_val); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - if (eql) { - copy_const_val(ira->codegen, stored_val, new_val); - set_optional_value_to_null(result->value); - } else { - set_optional_payload(result->value, stored_val); - } - return result; - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, result_type)) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true, true); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - } else { - result_loc = nullptr; - } - - return ir_build_cmpxchg_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, - casted_ptr, casted_cmp_value, casted_new_value, - success_order, failure_order, instruction->is_weak, result_loc); -} - -static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, Scope *scope, AstNode *source_node, ReduceOp op, ZigValue *value, ZigValue *out_value) { - assert(value->type->id == ZigTypeIdVector); - ZigType *scalar_type = value->type->data.vector.elem_type; - const size_t len = value->type->data.vector.len; - assert(len > 0); - - out_value->type = scalar_type; - out_value->special = ConstValSpecialStatic; - - if (scalar_type->id == ZigTypeIdBool) { - ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0]; - - bool result = first_elem_val->data.x_bool; - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - switch (op) { - case ReduceOp_and: - result = result && elem_val->data.x_bool; - if (!result) break; // Short circuit - break; - case ReduceOp_or: - result = result || elem_val->data.x_bool; - if (result) break; // Short circuit - break; - case ReduceOp_xor: - result = result != elem_val->data.x_bool; - break; - default: - zig_unreachable(); - } - } - - out_value->data.x_bool = result; - return nullptr; - } - - // Evaluate and/or/xor. - if (op == ReduceOp_and || op == ReduceOp_or || op == ReduceOp_xor) { - ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0]; - - copy_const_val(ira->codegen, out_value, first_elem_val); - - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_and: bin_op = IrBinOpBinAnd; break; - case ReduceOp_or: bin_op = IrBinOpBinOr; break; - case ReduceOp_xor: bin_op = IrBinOpBinXor; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - out_value, bin_op, elem_val, out_value); - if (msg != nullptr) - return msg; - } - - return nullptr; - } - - // Evaluate add/sub. - // Perform the reduction sequentially, starting from the neutral value. - if (op == ReduceOp_add || op == ReduceOp_mul) { - if (scalar_type->id == ZigTypeIdInt) { - if (op == ReduceOp_add) { - bigint_init_unsigned(&out_value->data.x_bigint, 0); - } else { - bigint_init_unsigned(&out_value->data.x_bigint, 1); - } - } else { - if (op == ReduceOp_add) { - float_init_f64(out_value, -0.0); - } else { - float_init_f64(out_value, 1.0); - } - } - - for (size_t i = 0; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_add: bin_op = IrBinOpAdd; break; - case ReduceOp_mul: bin_op = IrBinOpMult; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - out_value, bin_op, elem_val, out_value); - if (msg != nullptr) - return msg; - } - - return nullptr; - } - - // Evaluate min/max. - ZigValue *candidate_elem_val = &value->data.x_array.data.s_none.elements[0]; - - ZigValue *dummy_cmp_value = ira->codegen->pass1_arena->create(); - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_min: bin_op = IrBinOpCmpLessThan; break; - case ReduceOp_max: bin_op = IrBinOpCmpGreaterThan; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, - elem_val, bin_op, candidate_elem_val, dummy_cmp_value); - if (msg != nullptr) - return msg; - - if (dummy_cmp_value->data.x_bool) - candidate_elem_val = elem_val; - } - - ira->codegen->pass1_arena->destroy(dummy_cmp_value); - copy_const_val(ira->codegen, out_value, candidate_elem_val); - - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_reduce(IrAnalyze *ira, Stage1ZirInstReduce *instruction) { - Stage1AirInst *op_inst = instruction->op->child; - if (type_is_invalid(op_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value_inst = instruction->value->child; - if (type_is_invalid(value_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *value_type = value_inst->value->type; - if (value_type->id != ZigTypeIdVector) { - ir_add_error(ira, value_inst, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ReduceOp op; - if (!ir_resolve_reduce_op(ira, op_inst, &op)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = value_type->data.vector.elem_type; - switch (elem_type->id) { - case ZigTypeIdInt: - break; - case ZigTypeIdBool: - if (op > ReduceOp_xor) { - ir_add_error(ira, op_inst, - buf_sprintf("invalid operation for '%s' type", - buf_ptr(&elem_type->name))); - return ira->codegen->invalid_inst_gen; - } break; - case ZigTypeIdFloat: - if (op < ReduceOp_min) { - ir_add_error(ira, op_inst, - buf_sprintf("invalid operation for '%s' type", - buf_ptr(&elem_type->name))); - return ira->codegen->invalid_inst_gen; - } break; - default: - // Vectors cannot have child types other than those listed above - zig_unreachable(); - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, elem_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, - get_the_one_possible_value(ira->codegen, elem_type)); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(value_inst)) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, elem_type); - if (ir_eval_reduce(ira, instruction->base.scope, instruction->base.source_node, op, value_inst->value, result->value)) - return ira->codegen->invalid_inst_gen; - return result; - } - - return ir_build_reduce_gen(ira, instruction->base.scope, instruction->base.source_node, op, value_inst, elem_type); -} - -static Stage1AirInst *ir_analyze_instruction_fence(IrAnalyze *ira, Stage1ZirInstFence *instruction) { - Stage1AirInst *order_inst = instruction->order->child; - if (type_is_invalid(order_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder order; - if (!ir_resolve_atomic_order(ira, order_inst, &order)) - return ira->codegen->invalid_inst_gen; - - if (order < AtomicOrderAcquire) { - ir_add_error(ira, order_inst, - buf_sprintf("atomic ordering must be Acquire or stricter")); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_fence_gen(ira, instruction->base.scope, instruction->base.source_node, order); -} - -static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirInstTruncate *instruction) { - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *operand = instruction->target->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_truncate(ira, instruction->base.scope, instruction->base.source_node, - dest_type, instruction->dest_type->source_node, - operand, instruction->target->source_node); -} - -static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, AstNode *dest_type_src_node, - Stage1AirInst *target, AstNode *target_src_node) -{ - ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ? - dest_type->data.vector.elem_type : dest_type; - - if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, dest_type_src_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ? - target->value->type->data.vector.elem_type : target->value->type; - - if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, target_src_node, buf_sprintf("expected integer type, found '%s'", - buf_ptr(&scalar_target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (scalar_dest_type->id == ZigTypeIdComptimeInt) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_implicit_cast2(ira, scope, target_src_node, target, dest_type); - } - - return ir_analyze_widen_or_shorten(ira, scope, source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirInstIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_cast(ira, instruction->base.scope, instruction->base.source_node, - dest_type, instruction->dest_type->source_node, - target, instruction->target->source_node); -} - -static Stage1AirInst *ir_analyze_instruction_float_cast(IrAnalyze *ira, Stage1ZirInstFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdFloat && dest_type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected float type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id == ZigTypeIdComptimeInt || - target->value->type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) { - CastOp op; - if (target->value->type->id == ZigTypeIdComptimeInt) { - op = CastOpIntToFloat; - } else { - op = CastOpNumLitToConcrete; - } - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, op); - } else { - return ira->codegen->invalid_inst_gen; - } - } - - if (target->value->type->id != ZigTypeIdFloat) { - ir_add_error_node(ira, instruction->target->source_node, buf_sprintf("expected float type, found '%s'", - buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - // XXX: This will trigger an assertion failure if dest_type is comptime_float - return ir_analyze_widen_or_shorten(ira, instruction->target->scope, - instruction->target->source_node, target, dest_type); - } - - return ir_analyze_widen_or_shorten(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, Stage1ZirInstErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_analyze_err_set_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { - Error err; - - ZigType *ptr_type; - if (is_slice(ty)) { - TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - } else { - ptr_type = get_src_ptr_type(ty); - } - assert(ptr_type != nullptr); - if (ptr_type->id == ZigTypeIdPointer) { - if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } else if (is_slice(ptr_type)) { - TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; - ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } - - *result_align = get_ptr_align(ira->codegen, ty); - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_int_to_float(IrAnalyze *ira, Stage1ZirInstIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdFloat && dest_type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected float type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdInt && target->value->type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected int type, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, CastOpIntToFloat); -} - -static Stage1AirInst *ir_analyze_instruction_float_to_int(IrAnalyze *ira, Stage1ZirInstFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id == ZigTypeIdComptimeInt) { - return ir_implicit_cast(ira, target, dest_type); - } - - if (target->value->type->id != ZigTypeIdFloat && target->value->type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, target->source_node, buf_sprintf("expected float type, found '%s'", - buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, CastOpFloatToInt); -} - -static Stage1AirInst *ir_analyze_instruction_err_to_int(IrAnalyze *ira, Stage1ZirInstErrToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target; - if (target->value->type->id == ZigTypeIdErrorSet) { - casted_target = target; - } else { - casted_target = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_global_error_set); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - } - - return ir_analyze_err_to_int(ira, instruction->base.scope, instruction->base.source_node, casted_target, ira->codegen->err_tag_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_err(IrAnalyze *ira, Stage1ZirInstIntToErr *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target = ir_implicit_cast(ira, target, ira->codegen->err_tag_type); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_err(ira, instruction->base.scope, instruction->base.source_node, casted_target, ira->codegen->builtin_types.entry_global_error_set); -} - -static Stage1AirInst *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, Stage1ZirInstBoolToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdBool) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected bool, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - bool is_true; - if (!ir_resolve_bool(ira, target, &is_true)) - return ira->codegen->invalid_inst_gen; - - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, is_true ? 1 : 0); - } - - ZigType *u1_type = get_int_type(ira->codegen, false, 1); - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, u1_type, CastOpBoolToInt); -} - -static Stage1AirInst *ir_analyze_instruction_vector_type(IrAnalyze *ira, Stage1ZirInstVectorType *instruction) { - uint64_t len; - if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = ir_resolve_vector_elem_type(ira, instruction->elem_type->child); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); - - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, vector_type); -} - -static Stage1AirInst *ir_analyze_shuffle_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *scalar_type, Stage1AirInst *a, Stage1AirInst *b, Stage1AirInst *mask) -{ - Error err; - src_assert(source_node && scalar_type && a && b && mask, source_node); - - if ((err = ir_validate_vector_elem_type(ira, source_node, scalar_type))) - return ira->codegen->invalid_inst_gen; - - uint32_t len_mask; - if (mask->value->type->id == ZigTypeIdVector) { - len_mask = mask->value->type->data.vector.len; - } else if (mask->value->type->id == ZigTypeIdArray) { - len_mask = mask->value->type->data.array.len; - } else { - ir_add_error(ira, mask, - buf_sprintf("expected vector or array, found '%s'", - buf_ptr(&mask->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - mask = ir_implicit_cast(ira, mask, get_vector_type(ira->codegen, len_mask, - ira->codegen->builtin_types.entry_i32)); - if (type_is_invalid(mask->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t len_a; - if (a->value->type->id == ZigTypeIdVector) { - len_a = a->value->type->data.vector.len; - } else if (a->value->type->id == ZigTypeIdArray) { - len_a = a->value->type->data.array.len; - } else if (a->value->type->id == ZigTypeIdUndefined) { - len_a = UINT32_MAX; - } else { - ir_add_error(ira, a, - buf_sprintf("expected vector or array with element type '%s', found '%s'", - buf_ptr(&scalar_type->name), - buf_ptr(&a->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t len_b; - if (b->value->type->id == ZigTypeIdVector) { - len_b = b->value->type->data.vector.len; - } else if (b->value->type->id == ZigTypeIdArray) { - len_b = b->value->type->data.array.len; - } else if (b->value->type->id == ZigTypeIdUndefined) { - len_b = UINT32_MAX; - } else { - ir_add_error(ira, b, - buf_sprintf("expected vector or array with element type '%s', found '%s'", - buf_ptr(&scalar_type->name), - buf_ptr(&b->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (len_a == UINT32_MAX && len_b == UINT32_MAX) { - return ir_const_undef(ira, a->scope, a->source_node, get_vector_type(ira->codegen, len_mask, scalar_type)); - } - - if (len_a == UINT32_MAX) { - len_a = len_b; - a = ir_const_undef(ira, a->scope, a->source_node, get_vector_type(ira->codegen, len_a, scalar_type)); - } else { - a = ir_implicit_cast(ira, a, get_vector_type(ira->codegen, len_a, scalar_type)); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (len_b == UINT32_MAX) { - len_b = len_a; - b = ir_const_undef(ira, b->scope, b->source_node, get_vector_type(ira->codegen, len_b, scalar_type)); - } else { - b = ir_implicit_cast(ira, b, get_vector_type(ira->codegen, len_b, scalar_type)); - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - } - - ZigValue *mask_val = ir_resolve_const(ira, mask, UndefOk); - if (mask_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, mask_val); - - for (uint32_t i = 0; i < len_mask; i += 1) { - ZigValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; - if (mask_elem_val->special == ConstValSpecialUndef) - continue; - int32_t v_i32 = bigint_as_signed(&mask_elem_val->data.x_bigint); - uint32_t v; - Stage1AirInst *chosen_operand; - if (v_i32 >= 0) { - v = (uint32_t)v_i32; - chosen_operand = a; - } else { - v = (uint32_t)~v_i32; - chosen_operand = b; - } - if (v >= chosen_operand->value->type->data.vector.len) { - ErrorMsg *msg = ir_add_error(ira, mask, - buf_sprintf("mask index '%u' has out-of-bounds selection", i)); - add_error_note(ira->codegen, msg, chosen_operand->source_node, - buf_sprintf("selected index '%u' out of bounds of %s", v, - buf_ptr(&chosen_operand->value->type->name))); - if (chosen_operand == a && v < len_a + len_b) { - add_error_note(ira->codegen, msg, b->source_node, - buf_create_from_str("selections from the second vector are specified with negative numbers")); - } - return ira->codegen->invalid_inst_gen; - } - } - - ZigType *result_type = get_vector_type(ira->codegen, len_mask, scalar_type); - if (instr_is_comptime(a) && instr_is_comptime(b)) { - ZigValue *a_val = ir_resolve_const(ira, a, UndefOk); - if (a_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *b_val = ir_resolve_const(ira, b, UndefOk); - if (b_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, a_val); - expand_undef_array(ira->codegen, b_val); - - Stage1AirInst *result = ir_const(ira, scope, source_node, result_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_mask); - for (uint32_t i = 0; i < mask_val->type->data.vector.len; i += 1) { - ZigValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - if (mask_elem_val->special == ConstValSpecialUndef) { - result_elem_val->special = ConstValSpecialUndef; - continue; - } - int32_t v = bigint_as_signed(&mask_elem_val->data.x_bigint); - // We've already checked for and emitted compile errors for index out of bounds here. - ZigValue *src_elem_val = (v >= 0) ? - &a->value->data.x_array.data.s_none.elements[v] : - &b->value->data.x_array.data.s_none.elements[~v]; - copy_const_val(ira->codegen, result_elem_val, src_elem_val); - - src_assert(result_elem_val->special == ConstValSpecialStatic, source_node); - } - result->value->special = ConstValSpecialStatic; - return result; - } - - // All static analysis passed, and not comptime. - // For runtime codegen, vectors a and b must be the same length. Here we - // recursively @shuffle the smaller vector to append undefined elements - // to it up to the length of the longer vector. This recursion terminates - // in 1 call because these calls to ir_analyze_shuffle_vector guarantee - // len_a == len_b. - if (len_a != len_b) { - uint32_t len_min = min(len_a, len_b); - uint32_t len_max = max(len_a, len_b); - - Stage1AirInst *expand_mask = ir_const(ira, mask->scope, mask->source_node, - get_vector_type(ira->codegen, len_max, ira->codegen->builtin_types.entry_i32)); - expand_mask->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_max); - uint32_t i = 0; - for (; i < len_min; i += 1) - bigint_init_unsigned(&expand_mask->value->data.x_array.data.s_none.elements[i].data.x_bigint, i); - for (; i < len_max; i += 1) - bigint_init_signed(&expand_mask->value->data.x_array.data.s_none.elements[i].data.x_bigint, -1); - - Stage1AirInst *undef = ir_const_undef(ira, scope, source_node, - get_vector_type(ira->codegen, len_min, scalar_type)); - - if (len_b < len_a) { - b = ir_analyze_shuffle_vector(ira, scope, source_node, scalar_type, b, undef, expand_mask); - } else { - a = ir_analyze_shuffle_vector(ira, scope, source_node, scalar_type, a, undef, expand_mask); - } - } - - return ir_build_shuffle_vector_gen(ira, scope, source_node, - result_type, a, b, mask); -} - -static Stage1AirInst *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, Stage1ZirInstShuffleVector *instruction) { - ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type->child); - if (type_is_invalid(scalar_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *a = instruction->a->child; - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *b = instruction->b->child; - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *mask = instruction->mask->child; - if (type_is_invalid(mask->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_shuffle_vector(ira, instruction->base.scope, instruction->base.source_node, scalar_type, a, b, mask); -} - -static Stage1AirInst *ir_analyze_instruction_select(IrAnalyze *ira, Stage1ZirInstSelect *instruction) { - Error err; - - ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type->child); - if (type_is_invalid(scalar_type)) - return ira->codegen->invalid_inst_gen; - - if ((err = ir_validate_vector_elem_type(ira, instruction->base.source_node, scalar_type))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *pred = instruction->pred->child; - if (type_is_invalid(pred->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *a = instruction->a->child; - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *b = instruction->b->child; - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - - if (pred->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, pred, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&pred->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t pred_len = pred->value->type->data.vector.len; - pred = ir_implicit_cast(ira, pred, get_vector_type(ira->codegen, pred_len, - ira->codegen->builtin_types.entry_bool)); - if (type_is_invalid(pred->value->type)) - return ira->codegen->invalid_inst_gen; - - if (a->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, a, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&a->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (b->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, b, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&b->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = get_vector_type(ira->codegen, pred_len, scalar_type); - - a = ir_implicit_cast(ira, a, result_type); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - b = ir_implicit_cast(ira, b, result_type); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(pred) && instr_is_comptime(a) && instr_is_comptime(b)) { - ZigValue *pred_val = ir_resolve_const(ira, pred, UndefBad); - if (pred_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *a_val = ir_resolve_const(ira, a, UndefBad); - if (a_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *b_val = ir_resolve_const(ira, b, UndefBad); - if (b_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, a_val); - expand_undef_array(ira->codegen, b_val); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(pred_len); - - for (uint64_t i = 0; i < pred_len; i += 1) { - ZigValue *dst_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - ZigValue *pred_elem_val = &pred_val->data.x_array.data.s_none.elements[i]; - ZigValue *a_elem_val = &a_val->data.x_array.data.s_none.elements[i]; - ZigValue *b_elem_val = &b_val->data.x_array.data.s_none.elements[i]; - ZigValue *result_elem_val = pred_elem_val->data.x_bool ? a_elem_val : b_elem_val; - copy_const_val(ira->codegen, dst_elem_val, result_elem_val); - } - - result->value->special = ConstValSpecialStatic; - return result; - } - - return ir_build_select_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, pred, a, b); -} - -static Stage1AirInst *ir_analyze_instruction_splat(IrAnalyze *ira, Stage1ZirInstSplat *instruction) { - Error err; - - Stage1AirInst *len = instruction->len->child; - if (type_is_invalid(len->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *scalar = instruction->scalar->child; - if (type_is_invalid(scalar->value->type)) - return ira->codegen->invalid_inst_gen; - - uint64_t len_u64; - if (!ir_resolve_unsigned(ira, len, ira->codegen->builtin_types.entry_u32, &len_u64)) - return ira->codegen->invalid_inst_gen; - uint32_t len_int = len_u64; - - if ((err = ir_validate_vector_elem_type(ira, scalar->source_node, scalar->value->type))) - return ira->codegen->invalid_inst_gen; - - ZigType *return_type = get_vector_type(ira->codegen, len_int, scalar->value->type); - - if (instr_is_comptime(scalar)) { - ZigValue *scalar_val = ir_resolve_const(ira, scalar, UndefOk); - if (scalar_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (scalar_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, return_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_int); - for (uint32_t i = 0; i < len_int; i += 1) { - copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], scalar_val); - } - return result; - } - - return ir_build_splat_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, scalar); -} - -static Stage1AirInst *ir_analyze_instruction_bool_not(IrAnalyze *ira, Stage1ZirInstBoolNot *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, bool_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *value = ir_resolve_const(ira, casted_value, UndefBad); - if (value == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, !value->data.x_bool); - } - - return ir_build_bool_not_gen(ira, instruction->base.scope, instruction->base.source_node, casted_value); -} - -static Stage1AirInst *ir_analyze_instruction_memset(IrAnalyze *ira, Stage1ZirInstMemset *instruction) { - Error err; - - Stage1AirInst *dest_ptr = instruction->dest_ptr->child; - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *byte_value = instruction->byte->child; - if (type_is_invalid(byte_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *count_value = instruction->count->child; - if (type_is_invalid(count_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_uncasted_type = dest_ptr->value->type; - bool dest_is_volatile = (dest_uncasted_type->id == ZigTypeIdPointer) && - dest_uncasted_type->data.pointer.is_volatile; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - ZigType *u8 = ira->codegen->builtin_types.entry_u8; - uint32_t dest_align; - if (dest_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) - return ira->codegen->invalid_inst_gen; - } else { - dest_align = get_abi_alignment(ira->codegen, u8); - } - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, - PtrLenUnknown, dest_align, 0, 0, false); - - Stage1AirInst *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr); - if (type_is_invalid(casted_dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_byte = ir_implicit_cast(ira, byte_value, u8); - if (type_is_invalid(casted_byte->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_count = ir_implicit_cast(ira, count_value, usize); - if (type_is_invalid(casted_count->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO test this at comptime with u8 and non-u8 types - if (instr_is_comptime(casted_dest_ptr) && - instr_is_comptime(casted_byte) && - instr_is_comptime(casted_count)) - { - ZigValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); - if (dest_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); - if (byte_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); - if (count_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (casted_dest_ptr->value->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - casted_dest_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - ZigValue *dest_elements; - size_t start; - size_t bound_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - start = 0; - bound_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - bound_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memset on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memset on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memset on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memset on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memset on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memset on null ptr"); - } - - size_t count = bigint_as_usize(&count_val->data.x_bigint); - size_t end = start + count; - if (end > bound_end) { - ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - for (size_t i = start; i < end; i += 1) { - copy_const_val(ira->codegen, &dest_elements[i], byte_val); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - } - - return ir_build_memset_gen(ira, instruction->base.scope, instruction->base.source_node, casted_dest_ptr, casted_byte, casted_count); -} - -static Stage1AirInst *ir_analyze_instruction_memcpy(IrAnalyze *ira, Stage1ZirInstMemcpy *instruction) { - Error err; - - Stage1AirInst *dest_ptr = instruction->dest_ptr->child; - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *src_ptr = instruction->src_ptr->child; - if (type_is_invalid(src_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *count_value = instruction->count->child; - if (type_is_invalid(count_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u8 = ira->codegen->builtin_types.entry_u8; - ZigType *dest_uncasted_type = dest_ptr->value->type; - ZigType *src_uncasted_type = src_ptr->value->type; - bool dest_is_volatile = (dest_uncasted_type->id == ZigTypeIdPointer) && - dest_uncasted_type->data.pointer.is_volatile; - bool src_is_volatile = (src_uncasted_type->id == ZigTypeIdPointer) && - src_uncasted_type->data.pointer.is_volatile; - - uint32_t dest_align; - if (dest_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) - return ira->codegen->invalid_inst_gen; - } else { - dest_align = get_abi_alignment(ira->codegen, u8); - } - - uint32_t src_align; - if (src_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, src_uncasted_type, &src_align))) - return ira->codegen->invalid_inst_gen; - } else { - src_align = get_abi_alignment(ira->codegen, u8); - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, - PtrLenUnknown, dest_align, 0, 0, false); - ZigType *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, - PtrLenUnknown, src_align, 0, 0, false); - - Stage1AirInst *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut); - if (type_is_invalid(casted_dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_src_ptr = ir_implicit_cast(ira, src_ptr, u8_ptr_const); - if (type_is_invalid(casted_src_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_count = ir_implicit_cast(ira, count_value, usize); - if (type_is_invalid(casted_count->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO test this at comptime with u8 and non-u8 types - // TODO test with dest ptr being a global runtime variable - if (instr_is_comptime(casted_dest_ptr) && - instr_is_comptime(casted_src_ptr) && - instr_is_comptime(casted_count)) - { - ZigValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); - if (dest_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad); - if (src_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); - if (count_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - size_t count = bigint_as_usize(&count_val->data.x_bigint); - - ZigValue *dest_elements; - size_t dest_start; - size_t dest_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - dest_start = 0; - dest_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - dest_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } - - if (dest_start + count > dest_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *src_elements; - size_t src_start; - size_t src_end; - - switch (src_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; - src_start = 0; - src_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - src_elements = array_val->data.x_array.data.s_none.elements; - src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; - src_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } - - if (src_start + count > src_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - // TODO check for noalias violations - this should be generalized to work for any function - - for (size_t i = 0; i < count; i += 1) { - copy_const_val(ira->codegen, &dest_elements[dest_start + i], &src_elements[src_start + i]); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - } - - return ir_build_memcpy_gen(ira, instruction->base.scope, instruction->base.source_node, casted_dest_ptr, casted_src_ptr, casted_count); -} - -static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) { - if (result_loc == nullptr) return nullptr; - - if (result_loc->id == ResultLocIdCast) { - return ir_resolve_type(ira, result_loc->source_instruction->child); - } - - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_slice(IrAnalyze *ira, Stage1ZirInstSlice *instruction) { - Error err; - - Stage1AirInst *ptr_ptr = instruction->ptr->child; - if (type_is_invalid(ptr_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_ptr_type = ptr_ptr->value->type; - assert(ptr_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = ptr_ptr_type->data.pointer.child_type; - - Stage1AirInst *start = instruction->start->child; - if (type_is_invalid(start->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_start = ir_implicit_cast(ira, start, usize); - if (type_is_invalid(casted_start->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end; - if (instruction->end) { - end = instruction->end->child; - if (type_is_invalid(end->value->type)) - return ira->codegen->invalid_inst_gen; - end = ir_implicit_cast(ira, end, usize); - if (type_is_invalid(end->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - end = nullptr; - } - - ZigValue *slice_sentinel_val = nullptr; - ZigType *non_sentinel_slice_ptr_type; - ZigType *elem_type; - - bool generate_non_null_assert = false; - - if (array_type->id == ZigTypeIdArray) { - elem_type = array_type->data.array.child_type; - non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, - ptr_ptr_type->data.pointer.is_const, - ptr_ptr_type->data.pointer.is_volatile, - PtrLenUnknown, - ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); - } else if (array_type->id == ZigTypeIdPointer) { - if (array_type->data.pointer.ptr_len == PtrLenSingle) { - ZigType *main_type = array_type->data.pointer.child_type; - if (main_type->id == ZigTypeIdArray) { - elem_type = main_type->data.pointer.child_type; - non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, - elem_type, - array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, - PtrLenUnknown, - array_type->data.pointer.explicit_alignment, 0, 0, false); - } else { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of single-item pointer")); - return ira->codegen->invalid_inst_gen; - } - } else { - elem_type = array_type->data.pointer.child_type; - if (array_type->data.pointer.ptr_len == PtrLenC) { - array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); - - // C pointers are allowzero by default. - // However, we want to be able to slice them without generating an allowzero slice (see issue #4401). - // To achieve this, we generate a runtime safety check and make the slice type non-allowzero. - if (array_type->data.pointer.allow_zero) { - array_type = adjust_ptr_allow_zero(ira->codegen, array_type, false); - generate_non_null_assert = true; - } - } - ZigType *maybe_sentineled_slice_ptr_type = array_type; - non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); - if (!end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of pointer must include end value")); - return ira->codegen->invalid_inst_gen; - } - } - } else if (is_slice(array_type)) { - ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel; - non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); - elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel_val = nullptr; - if (instruction->sentinel) { - Stage1AirInst *uncasted_sentinel = instruction->sentinel->child; - if (type_is_invalid(uncasted_sentinel->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *sentinel = ir_implicit_cast(ira, uncasted_sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ira->codegen->invalid_inst_gen; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && - array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; - - ZigType *return_type; - - // If start index and end index are both comptime known, then the result type is a pointer to array - // not a slice. However, if the start or end index is a lazy value, and the result location is a slice, - // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these - // values by making the return type a slice. - ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); - bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type)); - bool end_is_known = !result_loc_is_slice && - ((end != nullptr && value_is_comptime(end->value)) || - (end == nullptr && child_array_type->id == ZigTypeIdArray)); - - ZigValue *array_sentinel = sentinel_val; - if (end_is_known) { - uint64_t end_scalar; - if (end != nullptr) { - ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - end_scalar = bigint_as_u64(&end_val->data.x_bigint); - } else { - end_scalar = child_array_type->data.array.len; - } - array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len) - ? child_array_type->data.array.sentinel : sentinel_val; - - if (value_is_comptime(casted_start->value)) { - ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); - - if (start_scalar > end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - - uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; - uint32_t ptr_byte_alignment = 0; - if (end_scalar > start_scalar) { - if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) - return ira->codegen->invalid_inst_gen; - } - - ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, - array_sentinel); - return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, - non_sentinel_slice_ptr_type->data.pointer.is_const, - non_sentinel_slice_ptr_type->data.pointer.is_volatile, - PtrLenSingle, ptr_byte_alignment, 0, 0, false); - goto done_with_return_type; - } - } else if (array_sentinel == nullptr && end == nullptr) { - array_sentinel = slice_sentinel_val; - } - if (array_sentinel != nullptr) { - // TODO deal with non-abi-alignment here - ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel); - return_type = get_slice_type(ira->codegen, slice_ptr_type); - } else { - // TODO deal with non-abi-alignment here - return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); - } -done_with_return_type: - - if (instr_is_comptime(ptr_ptr) && - value_is_comptime(casted_start->value) && - (!end || value_is_comptime(end->value))) - { - ZigValue *array_val; - ZigValue *parent_ptr; - size_t abs_offset; - size_t rel_end; - bool ptr_is_undef = false; - if (child_array_type->id == ZigTypeIdArray) { - if (array_type->id == ZigTypeIdPointer) { - parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (parent_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (parent_ptr->special == ConstValSpecialUndef) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - ptr_is_undef = true; - } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - } else { - array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.source_node); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - - rel_end = child_array_type->data.array.len; - abs_offset = 0; - } - } else { - array_val = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - rel_end = array_type->data.array.len; - parent_ptr = nullptr; - abs_offset = 0; - } - } else if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.ptr_len == PtrLenUnknown); - parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (parent_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (parent_ptr->special == ConstValSpecialUndef) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - ptr_is_undef = true; - } else switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - if (parent_ptr->data.x_ptr.data.ref.pointee->type->id == ZigTypeIdArray) { - array_val = parent_ptr->data.x_ptr.data.ref.pointee; - abs_offset = 0; - rel_end = array_val->type->data.array.len; - } else { - array_val = nullptr; - abs_offset = SIZE_MAX; - rel_end = 1; - } - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - array_val = parent_ptr->data.x_ptr.data.base_array.array_val; - abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; - rel_end = array_val->type->data.array.len - abs_offset; - break; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - break; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null ptr"); - } - } else if (is_slice(array_type)) { - ZigValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (slice_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (slice_ptr->special == ConstValSpecialUndef) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of undefined")); - return ira->codegen->invalid_inst_gen; - } - - parent_ptr = slice_ptr->data.x_struct.fields[slice_ptr_index]; - if (parent_ptr->special == ConstValSpecialUndef) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of undefined")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *len_val = slice_ptr->data.x_struct.fields[slice_len_index]; - - switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - array_val = nullptr; - abs_offset = SIZE_MAX; - rel_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - array_val = parent_ptr->data.x_ptr.data.base_array.array_val; - abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; - rel_end = bigint_as_usize(&len_val->data.x_bigint); - break; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - array_val = nullptr; - abs_offset = 0; - rel_end = bigint_as_usize(&len_val->data.x_bigint); - break; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of slice cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null"); - } - } else { - zig_unreachable(); - } - - ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); - if (!ptr_is_undef && start_scalar > rel_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - - uint64_t end_scalar = rel_end; - if (end) { - ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - end_scalar = bigint_as_u64(&end_val->data.x_bigint); - } - if (!ptr_is_undef) { - if (end_scalar > rel_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - if (start_scalar > end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice start is greater than end")); - return ira->codegen->invalid_inst_gen; - } - } - if (ptr_is_undef && start_scalar != end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("non-zero length slice of undefined pointer")); - return ira->codegen->invalid_inst_gen; - } - - // check sentinel when target is comptime-known - { - if (!sentinel_val) - goto exit_check_sentinel; - - switch (ptr_ptr->value->data.x_ptr.mut) { - case ConstPtrMutComptimeConst: - case ConstPtrMutComptimeVar: - break; - case ConstPtrMutRuntimeVar: - case ConstPtrMutInfer: - goto exit_check_sentinel; - } - - // prepare check parameters - ZigValue *target = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (target == nullptr) - return ira->codegen->invalid_inst_gen; - - uint64_t target_len = 0; - ZigValue *target_sentinel = nullptr; - ZigValue *target_elements = nullptr; - - for (;;) { - if (target->type->id == ZigTypeIdArray) { - // handle `[N]T` - target_len = target->type->data.array.len; - target_sentinel = target->type->data.array.sentinel; - expand_undef_array(ira->codegen, target); - target_elements = target->data.x_array.data.s_none.elements; - break; - } else if (target->type->id == ZigTypeIdPointer && target->type->data.pointer.child_type->id == ZigTypeIdArray) { - // handle `*[N]T` - target = const_ptr_pointee(ira, ira->codegen, target, instruction->base.source_node); - if (target == nullptr) - return ira->codegen->invalid_inst_gen; - assert(target->type->id == ZigTypeIdArray); - continue; - } else if (target->type->id == ZigTypeIdPointer) { - // handle `[*]T` - // handle `[*c]T` - switch (target->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - target = target->data.x_ptr.data.ref.pointee; - assert(target->type->id == ZigTypeIdArray); - continue; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - target = target->data.x_ptr.data.base_array.array_val; - assert(target->type->id == ZigTypeIdArray); - continue; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - // skip check - goto exit_check_sentinel; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null ptr"); - } - break; - } else if (is_slice(target->type)) { - // handle `[]T` - target = target->data.x_struct.fields[slice_ptr_index]; - assert(target->type->id == ZigTypeIdPointer); - continue; - } - - zig_unreachable(); - } - - // perform check - if (target_sentinel == nullptr) { - if (end_scalar >= target_len) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel is out of bounds")); - return ira->codegen->invalid_inst_gen; - } - if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match memory at target index")); - return ira->codegen->invalid_inst_gen; - } - } else { - assert(end_scalar <= target_len); - if (end_scalar == target_len) { - if (!const_values_equal(ira->codegen, sentinel_val, target_sentinel)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match target-sentinel")); - return ira->codegen->invalid_inst_gen; - } - } else { - if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match memory at target index")); - return ira->codegen->invalid_inst_gen; - } - } - } - } - exit_check_sentinel: - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - - ZigValue *ptr_val; - if (return_type->id == ZigTypeIdPointer) { - // pointer to array - ptr_val = result->value; - } else { - // slice - result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - - ptr_val = result->value->data.x_struct.fields[slice_ptr_index]; - - ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index]; - init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); - } - - bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const; - if (array_val) { - size_t index = abs_offset + start_scalar; - init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); - if (return_type->id == ZigTypeIdPointer) { - ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; - } - if (array_type->id == ZigTypeIdArray) { - ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; - } else if (is_slice(array_type)) { - ptr_val->data.x_ptr.mut = parent_ptr->data.x_ptr.mut; - } else if (array_type->id == ZigTypeIdPointer) { - ptr_val->data.x_ptr.mut = parent_ptr->data.x_ptr.mut; - } - } else if (ptr_is_undef) { - ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, - return_type_is_const); - ptr_val->special = ConstValSpecialUndef; - } else switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, - return_type_is_const); - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - zig_unreachable(); - case ConstPtrSpecialBaseStruct: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseStruct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseErrorUnionCode"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseErrorUnionPayload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseOptionalPayload"); - case ConstPtrSpecialHardCodedAddr: - init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, - parent_ptr->type->data.pointer.child_type, - parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, - return_type_is_const); - break; - case ConstPtrSpecialFunction: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialFunction"); - case ConstPtrSpecialNull: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialNull"); - } - - // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type - result->value->type = return_type; - return result; - } - - if (generate_non_null_assert) { - Stage1AirInst *ptr_val = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, ptr_ptr, nullptr); - - if (type_is_invalid(ptr_val->value->type)) - return ira->codegen->invalid_inst_gen; - - ir_build_assert_non_null(ira, instruction->base.scope, instruction->base.source_node, ptr_val); - } - - Stage1AirInst *result_loc = nullptr; - - if (return_type->id != ZigTypeIdPointer) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - return_type, nullptr, true, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *dummy_value = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, - instruction->base.scope, instruction->base.source_node, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - } - } - - return ir_build_slice_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, ptr_ptr, - casted_start, end, instruction->safety_check_on, result_loc, sentinel_val); -} - -static Stage1AirInst *ir_analyze_instruction_has_field(IrAnalyze *ira, Stage1ZirInstHasField *instruction) { - Error err; - ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); - if (field_name == nullptr) - return ira->codegen->invalid_inst_gen; - - bool result; - if (container_type->id == ZigTypeIdStruct) { - result = find_struct_type_field(container_type, field_name) != nullptr; - } else if (container_type->id == ZigTypeIdEnum) { - result = find_enum_type_field(container_type, field_name) != nullptr; - } else if (container_type->id == ZigTypeIdUnion) { - result = find_union_type_field(container_type, field_name) != nullptr; - } else { - ir_add_error_node(ira, instruction->container_type->source_node, - buf_sprintf("type '%s' does not support @hasField", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, result); -} - -static Stage1AirInst *ir_analyze_instruction_wasm_memory_size(IrAnalyze *ira, Stage1ZirInstWasmMemorySize *instruction) { - // TODO generate compile error for target_arch different than 32bit - if (!target_is_wasm(ira->codegen->zig_target)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@wasmMemorySize is a wasm32 feature only")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *index = instruction->index->child; - if (type_is_invalid(index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u32 = ira->codegen->builtin_types.entry_u32; - - Stage1AirInst *casted_index = ir_implicit_cast(ira, index, u32); - if (type_is_invalid(casted_index->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_wasm_memory_size_gen(ira, instruction->base.scope, instruction->base.source_node, casted_index); -} - -static Stage1AirInst *ir_analyze_instruction_wasm_memory_grow(IrAnalyze *ira, Stage1ZirInstWasmMemoryGrow *instruction) { - // TODO generate compile error for target_arch different than 32bit - if (!target_is_wasm(ira->codegen->zig_target)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@wasmMemoryGrow is a wasm32 feature only")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *index = instruction->index->child; - if (type_is_invalid(index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u32 = ira->codegen->builtin_types.entry_u32; - - Stage1AirInst *casted_index = ir_implicit_cast(ira, index, u32); - if (type_is_invalid(casted_index->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *delta = instruction->delta->child; - if (type_is_invalid(delta->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_delta = ir_implicit_cast(ira, delta, u32); - if (type_is_invalid(casted_delta->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_wasm_memory_grow_gen(ira, instruction->base.scope, instruction->base.source_node, casted_index, casted_delta); -} - -static Stage1AirInst *ir_analyze_instruction_breakpoint(IrAnalyze *ira, Stage1ZirInstBreakpoint *instruction) { - return ir_build_breakpoint_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_return_address(IrAnalyze *ira, Stage1ZirInstReturnAddress *instruction) { - return ir_build_return_address_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_frame_address(IrAnalyze *ira, Stage1ZirInstFrameAddress *instruction) { - return ir_build_frame_address_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_frame_handle(IrAnalyze *ira, Stage1ZirInstFrameHandle *instruction) { - ZigFn *fn = ira->fn; - src_assert(fn != nullptr, instruction->base.source_node); - - if (fn->inferred_async_node == nullptr) { - fn->inferred_async_node = instruction->base.source_node; - } - - ZigType *frame_type = get_fn_frame_type(ira->codegen, fn); - ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false); - - return ir_build_handle_gen(ira, instruction->base.scope, instruction->base.source_node, ptr_frame_type); -} - -static Stage1AirInst *ir_analyze_instruction_frame_type(IrAnalyze *ira, Stage1ZirInstFrameType *instruction) { - ZigFn *fn = ir_resolve_fn(ira, instruction->fn->child); - if (fn == nullptr) - return ira->codegen->invalid_inst_gen; - - if (fn->type_entry->data.fn.is_generic) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@Frame() of generic function")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *ty = get_fn_frame_type(ira->codegen, fn); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ty); -} - -static Stage1AirInst *ir_analyze_instruction_frame_size(IrAnalyze *ira, Stage1ZirInstFrameSize *instruction) { - Stage1AirInst *fn = instruction->fn->child; - if (type_is_invalid(fn->value->type)) - return ira->codegen->invalid_inst_gen; - - if (fn->value->type->id != ZigTypeIdFn) { - ir_add_error(ira, fn, - buf_sprintf("expected function, found '%s'", buf_ptr(&fn->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ira->codegen->need_frame_size_prefix_data = true; - - return ir_build_frame_size_gen(ira, instruction->base.scope, instruction->base.source_node, fn); -} - -static Stage1AirInst *ir_analyze_instruction_align_of(IrAnalyze *ira, Stage1ZirInstAlignOf *instruction) { - // Here we create a lazy value in order to avoid resolving the alignment of the type - // immediately. This avoids false positive dependency loops such as: - // const Node = struct { - // field: []align(@alignOf(Node)) Node, - // }; - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - result->value->special = ConstValSpecialLazy; - - LazyValueAlignOf *lazy_align_of = heap::c_allocator.create(); - lazy_align_of->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_align_of->base; - lazy_align_of->base.id = LazyValueIdAlignOf; - - lazy_align_of->target_type = instruction->type_value->child; - if (ir_resolve_type_lazy(ira, lazy_align_of->target_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_overflow_op(IrAnalyze *ira, Stage1ZirInstOverflowOp *instruction) { - Error err; - - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdInt) { - ir_add_error(ira, type_value, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2; - if (instruction->op == IrOverflowOpShl) { - ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - dest_type->data.integral.bit_count - 1); - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - } else { - casted_op2 = ir_implicit_cast(ira, op2, dest_type); - } - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_ptr = instruction->result_ptr->child; - if (type_is_invalid(result_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *expected_ptr_type; - if (result_ptr->value->type->id == ZigTypeIdPointer) { - uint32_t alignment; - if ((err = resolve_ptr_align(ira, result_ptr->value->type, &alignment))) - return ira->codegen->invalid_inst_gen; - expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type, - false, result_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - alignment, 0, 0, false); - } else { - expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false); - } - - Stage1AirInst *casted_result_ptr = ir_implicit_cast(ira, result_ptr, expected_ptr_type); - if (type_is_invalid(casted_result_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - // Don't write anything to the result pointer. - if (dest_type->data.integral.bit_count == 0) - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - - if (instr_is_comptime(casted_op1) && - instr_is_comptime(casted_op2) && - instr_is_comptime(casted_result_ptr)) - { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *result_val = ir_resolve_const(ira, casted_result_ptr, UndefBad); - if (result_val == nullptr) - return ira->codegen->invalid_inst_gen; - - BigInt *op1_bigint = &op1_val->data.x_bigint; - BigInt *op2_bigint = &op2_val->data.x_bigint; - ZigValue *pointee_val = const_ptr_pointee(ira, ira->codegen, result_val, - casted_result_ptr->source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - BigInt *dest_bigint = &pointee_val->data.x_bigint; - switch (instruction->op) { - case IrOverflowOpAdd: - bigint_add(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpSub: - bigint_sub(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpMul: - bigint_mul(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpShl: - bigint_shl(dest_bigint, op1_bigint, op2_bigint); - break; - } - bool result_bool = false; - if (!bigint_fits_in_bits(dest_bigint, dest_type->data.integral.bit_count, - dest_type->data.integral.is_signed)) - { - result_bool = true; - BigInt tmp_bigint; - bigint_init_bigint(&tmp_bigint, dest_bigint); - bigint_truncate(dest_bigint, &tmp_bigint, dest_type->data.integral.bit_count, - dest_type->data.integral.is_signed); - } - pointee_val->special = ConstValSpecialStatic; - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, result_bool); - } - - return ir_build_overflow_op_gen(ira, instruction->base.scope, instruction->base.source_node, instruction->op, - casted_op1, casted_op2, casted_result_ptr, dest_type); -} - -static void ir_eval_mul_add(IrAnalyze *ira, ZigType *float_type, - ZigValue *op1, ZigValue *op2, ZigValue *op3, ZigValue *out_val) { - if (float_type->id == ZigTypeIdComptimeFloat) { - f128M_mulAdd(&out_val->data.x_bigfloat.value, &op1->data.x_bigfloat.value, &op2->data.x_bigfloat.value, - &op3->data.x_bigfloat.value); - } else if (float_type->id == ZigTypeIdFloat) { - switch (float_type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_mulAdd(op1->data.x_f16, op2->data.x_f16, op3->data.x_f16); - break; - case 32: - out_val->data.x_f32 = fmaf(op1->data.x_f32, op2->data.x_f32, op3->data.x_f32); - break; - case 64: - out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64); - break; - case 80: - zig_panic("compiler bug: TODO: implement 'mulAdd' for type 'f80'. See https://github.com/ziglang/zig/issues/4026"); - case 128: - f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static Stage1AirInst *ir_analyze_instruction_mul_add(IrAnalyze *ira, Stage1ZirInstMulAdd *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *expr_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - // Only allow float types, and vectors of floats. - ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; - if (float_type->id != ZigTypeIdFloat) { - ir_add_error(ira, type_value, - buf_sprintf("expected float or vector of float type, found '%s'", buf_ptr(&float_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, expr_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, expr_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op3 = instruction->op3->child; - if (type_is_invalid(op3->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op3 = ir_implicit_cast(ira, op3, expr_type); - if (type_is_invalid(casted_op3->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_op1) && - instr_is_comptime(casted_op2) && - instr_is_comptime(casted_op3)) { - ZigValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); - if (!op1_const) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_const = ir_resolve_const(ira, casted_op2, UndefBad); - if (!op2_const) - return ira->codegen->invalid_inst_gen; - ZigValue *op3_const = ir_resolve_const(ira, casted_op3, UndefBad); - if (!op3_const) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - ZigValue *out_val = result->value; - - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op1_const); - expand_undef_array(ira->codegen, op2_const); - expand_undef_array(ira->codegen, op3_const); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = expr_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_operand_op2 = &op2_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_operand_op3 = &op3_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(float_operand_op1->type == float_type); - assert(float_operand_op2->type == float_type); - assert(float_operand_op3->type == float_type); - assert(float_out_val->type == float_type); - ir_eval_mul_add(ira, float_type, - op1_const, op2_const, op3_const, float_out_val); - float_out_val->type = float_type; - } - out_val->type = expr_type; - out_val->special = ConstValSpecialStatic; - } else { - ir_eval_mul_add(ira, float_type, op1_const, op2_const, op3_const, out_val); - } - return result; - } - - return ir_build_mul_add_gen(ira, instruction->base.scope, instruction->base.source_node, casted_op1, casted_op2, casted_op3, expr_type); -} - -static Stage1AirInst *ir_analyze_instruction_test_err(IrAnalyze *ira, Stage1ZirInstTestErr *instruction) { - Stage1AirInst *base_ptr = instruction->base_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value; - if (instruction->base_ptr_is_payload) { - value = base_ptr; - } else { - value = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - base_ptr, nullptr); - } - - ZigType *type_entry = value->value->type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - if (type_entry->id == ZigTypeIdErrorUnion) { - if (instr_is_comptime(value)) { - ZigValue *err_union_val = ir_resolve_const(ira, value, UndefBad); - if (!err_union_val) - return ira->codegen->invalid_inst_gen; - - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, (err != nullptr)); - } - } - - if (instruction->resolve_err_set) { - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (!type_is_global_error_set(err_set_type) && - err_set_type->data.error_set.err_count == 0) - { - assert(!err_set_type->data.error_set.incomplete); - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } - } - - return ir_build_test_err_gen(ira, instruction->base.scope, instruction->base.source_node, value); - } else if (type_entry->id == ZigTypeIdErrorSet) { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, true); - } else { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } -} - -static Stage1AirInst *ir_analyze_unwrap_err_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool initializing) -{ - ZigType *ptr_type = base_ptr->value->type; - - // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, err_set_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, - ptr_type->data.pointer.explicit_alignment, 0, 0, false); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar && - ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) - { - ZigValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (initializing && err_union_val->special == ConstValSpecialUndef) { - ZigValue *vals = ira->codegen->pass1_arena->allocate(2); - ZigValue *err_set_val = &vals[0]; - ZigValue *payload_val = &vals[1]; - - err_set_val->special = ConstValSpecialUndef; - err_set_val->type = err_set_type; - err_set_val->parent.id = ConstParentIdErrUnionCode; - err_set_val->parent.data.p_err_union_code.err_union_val = err_union_val; - - payload_val->special = ConstValSpecialUndef; - payload_val->type = type_entry->data.error_union.payload_type; - payload_val->parent.id = ConstParentIdErrUnionPayload; - payload_val->parent.data.p_err_union_payload.err_union_val = err_union_val; - - err_union_val->special = ConstValSpecialStatic; - err_union_val->data.x_err_union.error_set = err_set_val; - err_union_val->data.x_err_union.payload = payload_val; - } - src_assert(err_union_val->special != ConstValSpecialRuntime, source_node); - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_unwrap_err_code_gen(ira, scope, - source_node, base_ptr, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode; - const_val->data.x_ptr.data.base_err_union_code.err_union_val = err_union_val; - const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - return result; - } - } - - return ir_build_unwrap_err_code_gen(ira, scope, source_node, base_ptr, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, Stage1ZirInstUnwrapErrCode *instruction) { - Stage1AirInst *base_ptr = instruction->err_union_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_unwrap_err_code(ira, instruction->base.scope, instruction->base.source_node, base_ptr, false); -} - -static Stage1AirInst *ir_analyze_unwrap_error_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing) -{ - ZigType *ptr_type = base_ptr->value->type; - - // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *payload_type = type_entry->data.error_union.payload_type; - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (initializing && err_union_val->special == ConstValSpecialUndef) { - ZigValue *vals = ira->codegen->pass1_arena->allocate(2); - ZigValue *err_set_val = &vals[0]; - ZigValue *payload_val = &vals[1]; - - err_set_val->special = ConstValSpecialStatic; - err_set_val->type = type_entry->data.error_union.err_set_type; - err_set_val->data.x_err_set = nullptr; - - payload_val->special = ConstValSpecialUndef; - payload_val->type = payload_type; - - err_union_val->special = ConstValSpecialStatic; - err_union_val->data.x_err_union.error_set = err_set_val; - err_union_val->data.x_err_union.payload = payload_val; - } - - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - if (err != nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_unwrap_err_payload_gen(ira, scope, - source_node, base_ptr, safety_check_on, initializing, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; - result->value->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - return result; - } - } - } - - return ir_build_unwrap_err_payload_gen(ira, scope, source_node, - base_ptr, safety_check_on, initializing, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, - Stage1ZirInstUnwrapErrPayload *instruction) -{ - assert(instruction->value->child); - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_unwrap_error_payload(ira, instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on, false); -} - -static Stage1AirInst *ir_analyze_instruction_fn_proto(IrAnalyze *ira, Stage1ZirInstFnProto *instruction) { - AstNode *proto_node = instruction->base.source_node; - assert(proto_node->type == NodeTypeFnProto); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueFnType *lazy_fn_type = heap::c_allocator.create(); - lazy_fn_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_fn_type->base; - lazy_fn_type->base.id = LazyValueIdFnType; - - if (proto_node->data.fn_proto.auto_err_set) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("inferring error set of return type valid only for function definitions")); - return ira->codegen->invalid_inst_gen; - } - - lazy_fn_type->cc = cc_from_fn_proto(&proto_node->data.fn_proto); - if (instruction->callconv_value != nullptr) { - ZigType *cc_enum_type = get_builtin_type(ira->codegen, "CallingConvention"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, instruction->callconv_value->child, cc_enum_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_value = ir_resolve_const(ira, casted_value, UndefBad); - if (const_value == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_fn_type->cc = (CallingConvention)bigint_as_u32(&const_value->data.x_enum_tag); - } - - size_t param_count = proto_node->data.fn_proto.params.length; - lazy_fn_type->proto_node = proto_node; - lazy_fn_type->param_types = heap::c_allocator.allocate(param_count); - - for (size_t param_index = 0; param_index < param_count; param_index += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) { - const CallingConvention cc = lazy_fn_type->cc; - - if (cc == CallingConventionC) { - break; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return ira->codegen->invalid_inst_gen; - } - } - - if (instruction->param_types[param_index] == nullptr) { - lazy_fn_type->is_generic = true; - return result; - } - - Stage1AirInst *param_type_value = instruction->param_types[param_index]->child; - if (type_is_invalid(param_type_value->value->type)) - return ira->codegen->invalid_inst_gen; - if (ir_resolve_const(ira, param_type_value, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - lazy_fn_type->param_types[param_index] = param_type_value; - } - - if (instruction->align_value != nullptr) { - lazy_fn_type->align_inst = instruction->align_value->child; - if (ir_resolve_const(ira, lazy_fn_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_fn_type->return_type = instruction->return_type->child; - if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_test_comptime(IrAnalyze *ira, Stage1ZirInstTestComptime *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, instr_is_comptime(value)); -} - -static Stage1AirInst *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, - Stage1ZirInstCheckSwitchProngs *instruction, bool have_underscore_prong) -{ - Stage1AirInst *target_value = instruction->target_value->child; - ZigType *switch_type = target_value->value->type; - if (type_is_invalid(switch_type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *original_value = ((Stage1ZirInstSwitchTarget *)(instruction->target_value))->target_value_ptr->child->value; - bool target_is_originally_union = original_value->type->id == ZigTypeIdPointer && - original_value->type->data.pointer.child_type->id == ZigTypeIdUnion; - - if (switch_type->id == ZigTypeIdEnum) { - HashMap field_prev_uses = {}; - field_prev_uses.init(switch_type->data.enumeration.src_field_count); - - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value_uncasted = range->start->child; - if (type_is_invalid(start_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *start_value = ir_implicit_cast(ira, start_value_uncasted, switch_type); - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value_uncasted = range->end->child; - if (type_is_invalid(end_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *end_value = ir_implicit_cast(ira, end_value_uncasted, switch_type); - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - assert(start_value->value->type->id == ZigTypeIdEnum); - BigInt start_index; - bigint_init_bigint(&start_index, &start_value->value->data.x_enum_tag); - - assert(end_value->value->type->id == ZigTypeIdEnum); - BigInt end_index; - bigint_init_bigint(&end_index, &end_value->value->data.x_enum_tag); - - if (bigint_cmp(&start_index, &end_index) == CmpGT) { - ir_add_error(ira, start_value, - buf_sprintf("range start value is greater than the end value")); - } - - BigInt field_index; - bigint_init_bigint(&field_index, &start_index); - for (;;) { - Cmp cmp = bigint_cmp(&field_index, &end_index); - if (cmp == CmpGT) { - break; - } - auto entry = field_prev_uses.put_unique(field_index, start_value->source_node); - if (entry) { - AstNode *prev_node = entry->value; - TypeEnumField *enum_field = find_enum_field_by_tag(switch_type, &field_index); - assert(enum_field != nullptr); - ErrorMsg *msg = ir_add_error(ira, start_value, - buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here")); - } - bigint_incr(&field_index); - } - } - if (have_underscore_prong) { - if (!switch_type->data.enumeration.non_exhaustive) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on exhaustive enum has `_` prong")); - } else if (target_is_originally_union) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("`_` prong not allowed when switching on tagged union")); - } - for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i]; - if (buf_eql_str(enum_field->name, "_")) - continue; - - auto entry = field_prev_uses.maybe_get(enum_field->value); - if (!entry) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - } - } - } else if (instruction->else_prong == nullptr) { - if (switch_type->data.enumeration.non_exhaustive && !target_is_originally_union) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong")); - } - for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i]; - - auto entry = field_prev_uses.maybe_get(enum_field->value); - if (!entry) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - } - } - } else if(!switch_type->data.enumeration.non_exhaustive && switch_type->data.enumeration.src_field_count == instruction->range_count) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (switch_type->id == ZigTypeIdErrorSet) { - if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - size_t field_prev_uses_count = ira->codegen->errors_by_index.length; - AstNode **field_prev_uses = heap::c_allocator.allocate(field_prev_uses_count); - - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value_uncasted = range->start->child; - if (type_is_invalid(start_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *start_value = ir_implicit_cast(ira, start_value_uncasted, switch_type); - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value_uncasted = range->end->child; - if (type_is_invalid(end_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *end_value = ir_implicit_cast(ira, end_value_uncasted, switch_type); - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - src_assert(start_value->value->type->id == ZigTypeIdErrorSet, instruction->base.source_node); - uint32_t start_index = start_value->value->data.x_err_set->value; - - src_assert(end_value->value->type->id == ZigTypeIdErrorSet, instruction->base.source_node); - uint32_t end_index = end_value->value->data.x_err_set->value; - - if (start_index != end_index) { - ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors")); - return ira->codegen->invalid_inst_gen; - } - - AstNode *prev_node = field_prev_uses[start_index]; - if (prev_node != nullptr) { - Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name; - ErrorMsg *msg = ir_add_error(ira, start_value, - buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name))); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here")); - } - field_prev_uses[start_index] = start_value->source_node; - } - if (instruction->else_prong == nullptr) { - if (type_is_global_error_set(switch_type)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("else prong required when switching on type 'anyerror'")); - return ira->codegen->invalid_inst_gen; - } else { - for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; - - AstNode *prev_node = field_prev_uses[err_entry->value]; - if (prev_node == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); - } - } - } - } - - heap::c_allocator.deallocate(field_prev_uses, field_prev_uses_count); - } else if (switch_type->id == ZigTypeIdInt) { - RangeSet rs = {0}; - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value = range->start->child; - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_start_value = ir_implicit_cast(ira, start_value, switch_type); - if (type_is_invalid(casted_start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value = range->end->child; - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_end_value = ir_implicit_cast(ira, end_value, switch_type); - if (type_is_invalid(casted_end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *start_val = ir_resolve_const(ira, casted_start_value, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *end_val = ir_resolve_const(ira, casted_end_value, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - - assert(start_val->type->id == ZigTypeIdInt || start_val->type->id == ZigTypeIdComptimeInt); - assert(end_val->type->id == ZigTypeIdInt || end_val->type->id == ZigTypeIdComptimeInt); - - if (bigint_cmp(&start_val->data.x_bigint, &end_val->data.x_bigint) == CmpGT) { - ir_add_error(ira, start_value, - buf_sprintf("range start value is greater than the end value")); - } - - AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, - start_value->source_node); - if (prev_node != nullptr) { - ErrorMsg *msg = ir_add_error(ira, start_value, buf_sprintf("duplicate switch value")); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("previous value here")); - return ira->codegen->invalid_inst_gen; - } - } - - BigInt min_val; - eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); - BigInt max_val; - eval_min_max_value_int(ira->codegen, switch_type, &max_val, true); - bool handles_all_cases = rangeset_spans(&rs, &min_val, &max_val); - if (!handles_all_cases && instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("switch must handle all possibilities")); - return ira->codegen->invalid_inst_gen; - } else if(handles_all_cases && instruction->else_prong != nullptr) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (switch_type->id == ZigTypeIdBool) { - int seenTrue = 0; - int seenFalse = 0; - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *value = range->start->child; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, switch_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_expr_val) - return ira->codegen->invalid_inst_gen; - - assert(const_expr_val->type->id == ZigTypeIdBool); - - if (const_expr_val->data.x_bool == true) { - seenTrue += 1; - } else { - seenFalse += 1; - } - - if ((seenTrue > 1) || (seenFalse > 1)) { - ir_add_error(ira, value, buf_sprintf("duplicate switch value")); - return ira->codegen->invalid_inst_gen; - } - } - if (((seenTrue < 1) || (seenFalse < 1)) && instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("switch must handle all possibilities")); - return ira->codegen->invalid_inst_gen; - } - - if(seenTrue == 1 && seenFalse == 1 && instruction->else_prong != nullptr) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); - return ira->codegen->invalid_inst_gen; - } else if(switch_type->id == ZigTypeIdMetaType) { - HashMap prevs; - // HashMap doubles capacity when reaching 60% capacity, - // because we know the size at init we can avoid reallocation by doubling it here - prevs.init(instruction->range_count * 2); - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *value = range->start->child; - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, switch_type); - if (type_is_invalid(casted_value->value->type)) { - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_expr_val) { - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - - auto entry = prevs.put_unique(const_expr_val->data.x_type, value); - if(entry != nullptr) { - ErrorMsg *msg = ir_add_error(ira, value, buf_sprintf("duplicate switch value")); - add_error_note(ira->codegen, msg, entry->value->source_node, buf_sprintf("previous value here")); - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - } - prevs.deinit(); - } - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_check_statement_is_void(IrAnalyze *ira, - Stage1ZirInstCheckStatementIsVoid *instruction) -{ - Stage1AirInst *statement_value = instruction->statement_value->child; - ZigType *statement_type = statement_value->value->type; - if (type_is_invalid(statement_type)) - return ira->codegen->invalid_inst_gen; - - if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) { - if(statement_type->id == ZigTypeIdErrorUnion || statement_type->id == ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("error is ignored. consider using `try`, `catch`, or `if`")); - }else{ - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("expression value is ignored")); - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_panic(IrAnalyze *ira, Stage1ZirInstPanic *instruction) { - Stage1AirInst *msg = instruction->msg->child; - if (type_is_invalid(msg->value->type)) - return ir_unreach_error(ira); - - if (ir_should_inline(ira->zir, instruction->base.scope)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("encountered @panic at compile-time")); - return ir_unreach_error(ira); - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); - Stage1AirInst *casted_msg = ir_implicit_cast(ira, msg, str_type); - if (type_is_invalid(casted_msg->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *new_instruction = ir_build_panic_gen(ira, instruction->base.scope, instruction->base.source_node, casted_msg); - return ir_finish_anal(ira, new_instruction); -} - -static Stage1AirInst *ir_align_cast(IrAnalyze *ira, Stage1AirInst *target, uint32_t align_bytes, bool safety_check_on) { - Error err; - - ZigType *target_type = target->value->type; - assert(!type_is_invalid(target_type)); - - ZigType *result_type; - uint32_t old_align_bytes; - - ZigType *actual_ptr = target_type; - if (actual_ptr->id == ZigTypeIdOptional) { - actual_ptr = actual_ptr->data.maybe.child_type; - } else if (is_slice(actual_ptr)) { - actual_ptr = actual_ptr->data.structure.fields[slice_ptr_index]->type_entry; - } - - if (safety_check_on && !type_has_bits(ira->codegen, actual_ptr)) { - ir_add_error(ira, target, - buf_sprintf("cannot adjust alignment of zero sized type '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (target_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, target_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes); - } else if (target_type->id == ZigTypeIdFn) { - FnTypeId fn_type_id = target_type->data.fn.fn_type_id; - old_align_bytes = fn_type_id.alignment; - fn_type_id.alignment = align_bytes; - result_type = get_fn_type(ira->codegen, &fn_type_id); - } else if (target_type->id == ZigTypeIdAnyFrame) { - if (align_bytes >= get_async_frame_align_bytes(ira->codegen)) { - result_type = target_type; - } else { - ir_add_error(ira, target, buf_sprintf("sub-aligned anyframe not allowed")); - return ira->codegen->invalid_inst_gen; - } - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdPointer) - { - ZigType *ptr_type = target_type->data.maybe.child_type; - if ((err = resolve_ptr_align(ira, ptr_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - ZigType *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes); - - result_type = get_optional_type(ira->codegen, better_ptr_type); - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdFn) - { - FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id; - old_align_bytes = fn_type_id.alignment; - fn_type_id.alignment = align_bytes; - ZigType *fn_type = get_fn_type(ira->codegen, &fn_type_id); - result_type = get_optional_type(ira->codegen, fn_type); - } else if (is_slice(target_type)) { - ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((err = resolve_ptr_align(ira, slice_ptr_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - ZigType *result_ptr_type = adjust_ptr_align(ira->codegen, slice_ptr_type, align_bytes); - result_type = get_slice_type(ira->codegen, result_ptr_type); - } else { - ir_add_error(ira, target, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr % align_bytes != 0) - { - ir_add_error(ira, target, - buf_sprintf("pointer address 0x%" ZIG_PRI_x64 " is not aligned to %" PRIu32 " bytes", - val->data.x_ptr.data.hard_coded_addr.addr, align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, target->scope, target->source_node, result_type); - copy_const_val(ira->codegen, result->value, val); - result->value->type = result_type; - return result; - } - - if (safety_check_on && align_bytes > old_align_bytes && align_bytes != 1) { - return ir_build_align_cast_gen(ira, target->scope, target->source_node, target, result_type); - } else { - return ir_build_cast(ira, target->scope, target->source_node, result_type, target, CastOpNoop); - } -} - -static Stage1AirInst *ir_analyze_ptr_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AstNode *ptr_src, ZigType *dest_type, AstNode *dest_type_src, - bool safety_check_on, bool keep_bigger_alignment) -{ - Error err; - - ZigType *src_type = ptr->value->type; - assert(!type_is_invalid(src_type)); - - if (src_type == dest_type) { - return ptr; - } - - // We have a check for zero bits later so we use get_src_ptr_type to - // validate src_type and dest_type. - - ZigType *if_slice_ptr_type; - if (is_slice(src_type)) { - TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; - if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - } else { - if_slice_ptr_type = src_type; - - ZigType *src_ptr_type = get_src_ptr_type(src_type); - if (src_ptr_type == nullptr) { - ir_add_error_node(ira, ptr_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - ZigType *dest_ptr_type = get_src_ptr_type(dest_type); - if (dest_ptr_type == nullptr) { - ir_add_error_node(ira, dest_type_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) { - ir_add_error_node(ira, source_node, buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - uint32_t dest_align_bytes; - if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) - return ira->codegen->invalid_inst_gen; - - uint32_t src_align_bytes = 0; - if (keep_bigger_alignment || dest_align_bytes != 1) { - if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (safety_check_on && - type_has_bits(ira->codegen, dest_type) && - !type_has_bits(ira->codegen, if_slice_ptr_type)) - { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("'%s' and '%s' do not have the same in-memory representation", - buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); - add_error_note(ira->codegen, msg, ptr_src, - buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name))); - add_error_note(ira->codegen, msg, dest_type_src, - buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - // For slices, follow the `ptr` field. - if (is_slice(src_type)) { - TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; - Stage1AirInst *ptr_ref = ir_get_ref(ira, scope, source_node, ptr, true, false); - Stage1AirInst *ptr_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, ptr_field, ptr_ref, src_type, false); - ptr = ir_get_deref(ira, scope, source_node, ptr_ptr, nullptr); - } - - if (instr_is_comptime(ptr)) { - bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); - UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; - ZigValue *val = ir_resolve_const(ira, ptr, is_undef_allowed); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (value_is_comptime(val) && val->special != ConstValSpecialUndef) { - bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || - (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr == 0); - if (is_addr_zero && !dest_allows_addr_zero) { - ir_add_error_node(ira, source_node, - buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result; - if (val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_ptr_cast_gen(ira, scope, source_node, dest_type, ptr, safety_check_on); - } else { - result = ir_const(ira, scope, source_node, dest_type); - } - InferredStructField *isf = (val->type->id == ZigTypeIdPointer) ? - val->type->data.pointer.inferred_struct_field : nullptr; - if (isf == nullptr) { - copy_const_val(ira->codegen, result->value, val); - } else { - // The destination value should have x_ptr struct pointing to underlying struct value - result->value->data.x_ptr.mut = val->data.x_ptr.mut; - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = field->init_val; - } else { - assert(val->data.x_ptr.special == ConstPtrSpecialRef); - result->value->data.x_ptr.special = ConstPtrSpecialBaseStruct; - result->value->data.x_ptr.data.base_struct.struct_val = val->data.x_ptr.data.ref.pointee; - result->value->data.x_ptr.data.base_struct.field_index = field->src_index; - } - result->value->special = ConstValSpecialStatic; - } - result->value->type = dest_type; - - // Keep the bigger alignment, it can only help- unless the target is zero bits. - if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { - result = ir_align_cast(ira, result, src_align_bytes, false); - } - - return result; - } - - if (src_align_bytes != 0 && dest_align_bytes > src_align_bytes) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cast increases pointer alignment")); - add_error_note(ira->codegen, msg, ptr_src, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes)); - add_error_note(ira->codegen, msg, dest_type_src, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_ptr = ir_build_ptr_cast_gen(ira, scope, source_node, dest_type, ptr, safety_check_on); - - // Keep the bigger alignment, it can only help- unless the target is zero bits. - Stage1AirInst *result; - if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { - result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result = casted_ptr; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, Stage1ZirInstPtrCast *instruction) { - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = instruction->ptr->child; - ZigType *src_type = ptr->value->type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_inst_gen; - - // This logic is not quite right; this is just to get stage1 to accept valid code - // we use in the self-hosted compiler. - if (is_slice(dest_type) && is_slice(src_type)) { - return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, dest_type); - } - - bool keep_bigger_alignment = true; - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, - instruction->ptr->source_node, dest_type, dest_type_value->source_node, - instruction->safety_check_on, keep_bigger_alignment); -} - -static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue *val, size_t len) { - size_t buf_i = 0; - // TODO optimize the buf case - expand_undef_array(codegen, val); - for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { - ZigValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { - buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); - } -} - -static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { - if (val->special == ConstValSpecialUndef) { - expand_undef_struct(codegen, val); - val->special = ConstValSpecialStatic; - } - assert(val->special == ConstValSpecialStatic); - switch (val->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - zig_unreachable(); - case ZigTypeIdVoid: - return; - case ZigTypeIdBool: - buf[0] = val->data.x_bool ? 1 : 0; - return; - case ZigTypeIdInt: - bigint_write_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian); - return; - case ZigTypeIdEnum: - bigint_write_twos_complement(&val->data.x_enum_tag, buf, - val->type->data.enumeration.tag_int_type->data.integral.bit_count, - codegen->is_big_endian); - return; - case ZigTypeIdFloat: - float_write_ieee597(val, buf, codegen->is_big_endian); - return; - case ZigTypeIdPointer: - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - BigInt bn; - bigint_init_unsigned(&bn, val->data.x_ptr.data.hard_coded_addr.addr); - bigint_write_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, codegen->is_big_endian); - return; - } else { - zig_unreachable(); - } - case ZigTypeIdArray: - return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); - case ZigTypeIdVector: - return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); - case ZigTypeIdStruct: - switch (val->type->data.structure.layout) { - case ContainerLayoutAuto: - zig_unreachable(); - case ContainerLayoutExtern: { - size_t src_field_count = val->type->data.structure.src_field_count; - for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { - TypeStructField *struct_field = val->type->data.structure.fields[field_i]; - if (struct_field->gen_index == SIZE_MAX || struct_field->is_comptime) - continue; - ZigValue *field_val = val->data.x_struct.fields[field_i]; - size_t offset = struct_field->offset; - buf_write_value_bytes(codegen, buf + offset, field_val); - } - return; - } - case ContainerLayoutPacked: { - size_t src_field_count = val->type->data.structure.src_field_count; - size_t gen_field_count = val->type->data.structure.gen_field_count; - size_t gen_i = 0; - size_t src_i = 0; - size_t offset = 0; - bool is_big_endian = codegen->is_big_endian; - uint8_t child_buf_prealloc[16]; - size_t child_buf_len = 16; - uint8_t *child_buf = child_buf_prealloc; - while (gen_i < gen_field_count) { - size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i]; - if (big_int_byte_count > child_buf_len) { - child_buf = heap::c_allocator.allocate_nonzero(big_int_byte_count); - child_buf_len = big_int_byte_count; - } - BigInt big_int; - bigint_init_unsigned(&big_int, 0); - size_t used_bits = 0; - while (src_i < src_field_count) { - TypeStructField *field = val->type->data.structure.fields[src_i]; - if (field->is_comptime) { - src_i += 1; - continue; - } - assert(field->gen_index != SIZE_MAX); - if (field->gen_index != gen_i) - break; - uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry); - buf_write_value_bytes(codegen, child_buf, val->data.x_struct.fields[src_i]); - BigInt child_val; - bigint_read_twos_complement(&child_val, child_buf, packed_bits_size, is_big_endian, - false); - if (is_big_endian) { - BigInt shift_amt; - bigint_init_unsigned(&shift_amt, packed_bits_size); - BigInt shifted; - bigint_shl(&shifted, &big_int, &shift_amt); - bigint_or(&big_int, &shifted, &child_val); - } else { - BigInt shift_amt; - bigint_init_unsigned(&shift_amt, used_bits); - BigInt child_val_shifted; - bigint_shl(&child_val_shifted, &child_val, &shift_amt); - BigInt tmp; - bigint_or(&tmp, &big_int, &child_val_shifted); - big_int = tmp; - used_bits += packed_bits_size; - } - src_i += 1; - } - bigint_write_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian); - offset += big_int_byte_count; - gen_i += 1; - } - return; - } - } - zig_unreachable(); - case ZigTypeIdOptional: - zig_panic("TODO buf_write_value_bytes maybe type"); - case ZigTypeIdFn: - zig_panic("TODO buf_write_value_bytes fn type"); - case ZigTypeIdUnion: - zig_panic("TODO buf_write_value_bytes union type"); - case ZigTypeIdFnFrame: - zig_panic("TODO buf_write_value_bytes async fn frame type"); - case ZigTypeIdAnyFrame: - zig_panic("TODO buf_write_value_bytes anyframe type"); - } - zig_unreachable(); -} - -static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, - ZigValue *val, ZigType *elem_type, size_t len) -{ - Error err; - uint64_t elem_size = type_size(codegen, elem_type); - - switch (val->data.x_array.special) { - case ConstArraySpecialNone: - val->data.x_array.data.s_none.elements = codegen->pass1_arena->allocate(len); - for (size_t i = 0; i < len; i++) { - ZigValue *elem = &val->data.x_array.data.s_none.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = elem_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - case ConstArraySpecialUndef: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); - case ConstArraySpecialBuf: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); - } - zig_unreachable(); -} - -static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val) { - Error err; - src_assert(val->special == ConstValSpecialStatic, source_node); - switch (val->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - zig_unreachable(); - case ZigTypeIdVoid: - return ErrorNone; - case ZigTypeIdBool: - val->data.x_bool = (buf[0] != 0); - return ErrorNone; - case ZigTypeIdInt: - bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian, val->type->data.integral.is_signed); - return ErrorNone; - case ZigTypeIdFloat: - float_read_ieee597(val, buf, codegen->is_big_endian); - return ErrorNone; - case ZigTypeIdPointer: - { - val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - BigInt bn; - bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, - codegen->is_big_endian, false); - val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_usize(&bn); - return ErrorNone; - } - case ZigTypeIdArray: - return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, - val->type->data.array.len); - case ZigTypeIdVector: - return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, - val->type->data.vector.len); - case ZigTypeIdEnum: { - ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; - src_assert(tag_int_type->id == ZigTypeIdInt, source_node); - bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, - codegen->is_big_endian, tag_int_type->data.integral.is_signed); - return ErrorNone; - } case ZigTypeIdStruct: - switch (val->type->data.structure.layout) { - case ContainerLayoutAuto: { - switch(val->type->data.structure.special){ - case StructSpecialNone: - case StructSpecialInferredTuple: - case StructSpecialInferredStruct: { - ErrorMsg *msg = opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", - buf_ptr(&val->type->name))); - add_error_note(codegen, msg, val->type->data.structure.decl_node, - buf_sprintf("declared here")); - break; - } - case StructSpecialSlice: { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("slice '%s' cannot have its bytes reinterpreted", - buf_ptr(&val->type->name))); - break; - } - } - return ErrorSemanticAnalyzeFail; - } - case ContainerLayoutExtern: { - size_t src_field_count = val->type->data.structure.src_field_count; - val->data.x_struct.fields = alloc_const_vals_ptrs(codegen, src_field_count); - for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { - TypeStructField *struct_field = val->type->data.structure.fields[field_i]; - if (struct_field->is_comptime) - continue; - ZigValue *field_val = val->data.x_struct.fields[field_i]; - field_val->special = ConstValSpecialStatic; - field_val->type = struct_field->type_entry; - if (struct_field->gen_index == SIZE_MAX) - continue; - size_t offset = struct_field->offset; - uint8_t *new_buf = buf + offset; - if ((err = buf_read_value_bytes(ira, codegen, source_node, new_buf, field_val))) - return err; - } - return ErrorNone; - } - case ContainerLayoutPacked: { - size_t src_field_count = val->type->data.structure.src_field_count; - val->data.x_struct.fields = alloc_const_vals_ptrs(codegen, src_field_count); - size_t gen_field_count = val->type->data.structure.gen_field_count; - size_t gen_i = 0; - size_t src_i = 0; - size_t offset = 0; - bool is_big_endian = codegen->is_big_endian; - uint8_t child_buf_prealloc[16]; - size_t child_buf_len = 16; - uint8_t *child_buf = child_buf_prealloc; - while (gen_i < gen_field_count) { - size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i]; - if (big_int_byte_count > child_buf_len) { - child_buf = heap::c_allocator.allocate_nonzero(big_int_byte_count); - child_buf_len = big_int_byte_count; - } - BigInt big_int; - bigint_read_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian, false); - uint64_t bit_offset = 0; - while (src_i < src_field_count) { - TypeStructField *field = val->type->data.structure.fields[src_i]; - if (field->is_comptime) { - src_i += 1; - continue; - } - src_assert(field->gen_index != SIZE_MAX, source_node); - if (field->gen_index != gen_i) - break; - ZigValue *field_val = val->data.x_struct.fields[src_i]; - field_val->special = ConstValSpecialStatic; - field_val->type = field->type_entry; - uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry); - - BigInt child_val; - if (is_big_endian) { - BigInt packed_bits_size_bi; - bigint_init_unsigned(&packed_bits_size_bi, big_int_byte_count * 8 - packed_bits_size - bit_offset); - BigInt tmp; - bigint_shr(&tmp, &big_int, &packed_bits_size_bi); - bigint_truncate(&child_val, &tmp, packed_bits_size, false); - } else { - BigInt packed_bits_size_bi; - bigint_init_unsigned(&packed_bits_size_bi, packed_bits_size); - bigint_truncate(&child_val, &big_int, packed_bits_size, false); - BigInt tmp; - bigint_shr(&tmp, &big_int, &packed_bits_size_bi); - big_int = tmp; - } - - bigint_write_twos_complement(&child_val, child_buf, packed_bits_size, is_big_endian); - if ((err = buf_read_value_bytes(ira, codegen, source_node, child_buf, field_val))) { - return err; - } - - bit_offset += packed_bits_size; - src_i += 1; - } - offset += big_int_byte_count; - gen_i += 1; - } - return ErrorNone; - } - } - zig_unreachable(); - case ZigTypeIdOptional: - zig_panic("TODO buf_read_value_bytes maybe type"); - case ZigTypeIdErrorUnion: - zig_panic("TODO buf_read_value_bytes error union"); - case ZigTypeIdErrorSet: - zig_panic("TODO buf_read_value_bytes pure error type"); - case ZigTypeIdFn: - zig_panic("TODO buf_read_value_bytes fn type"); - case ZigTypeIdUnion: - zig_panic("TODO buf_read_value_bytes union type"); - case ZigTypeIdFnFrame: - zig_panic("TODO buf_read_value_bytes async fn frame type"); - case ZigTypeIdAnyFrame: - zig_panic("TODO buf_read_value_bytes anyframe type"); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_bit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *dest_type) -{ - Error err; - - ZigType *src_type = value->value->type; - src_assert(type_can_bit_cast(src_type), source_node); - src_assert(type_can_bit_cast(dest_type), source_node); - - if (dest_type->id == ZigTypeIdEnum) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast a value of type '%s'", buf_ptr(&dest_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("use @intToEnum for type coercion")); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - const bool src_is_ptr = handle_is_ptr(ira->codegen, src_type); - const bool dest_is_ptr = handle_is_ptr(ira->codegen, dest_type); - - const uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); - const uint64_t src_size_bytes = type_size(ira->codegen, src_type); - if (dest_size_bytes != src_size_bytes) { - ir_add_error_node(ira, source_node, - buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64, - buf_ptr(&dest_type->name), dest_size_bytes, - buf_ptr(&src_type->name), src_size_bytes)); - return ira->codegen->invalid_inst_gen; - } - - const uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); - const uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); - if (dest_size_bits != src_size_bits) { - ir_add_error_node(ira, source_node, - buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", - buf_ptr(&dest_type->name), dest_size_bits, - buf_ptr(&src_type->name), src_size_bits)); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - uint8_t *buf = heap::c_allocator.allocate_nonzero(src_size_bytes); - buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, ira->codegen, source_node, buf, result->value))) - return ira->codegen->invalid_inst_gen; - heap::c_allocator.deallocate(buf, src_size_bytes); - return result; - } - - if (dest_is_ptr && !src_is_ptr) { - // Spill the scalar into a local memory location and take its address - value = ir_get_ref(ira, scope, source_node, value, false, false); - } - - return ir_build_bit_cast_gen(ira, scope, source_node, value, dest_type); -} - -static Stage1AirInst *ir_analyze_int_to_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *ptr_type) -{ - Error err; - - src_assert(get_src_ptr_type(ptr_type) != nullptr, source_node); - src_assert(type_has_bits(ira->codegen, ptr_type), source_node); - - Stage1AirInst *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); - if (type_is_invalid(casted_int->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_int)) { - ZigValue *val = ir_resolve_const(ira, casted_int, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - uint64_t addr = bigint_as_u64(&val->data.x_bigint); - if (!ptr_allows_addr_zero(ptr_type) && addr == 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t align_bytes; - if ((err = resolve_ptr_align(ira, ptr_type, &align_bytes))) - return ira->codegen->invalid_inst_gen; - - if (addr != 0 && addr % align_bytes != 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("pointer type '%s' requires aligned address", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, ptr_type); - if (ptr_type->id == ZigTypeIdOptional && addr == 0) { - result->value->data.x_ptr.special = ConstPtrSpecialNull; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else { - result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - result->value->data.x_ptr.data.hard_coded_addr.addr = addr; - } - - return result; - } - - return ir_build_int_to_ptr_gen(ira, scope, source_node, casted_int, ptr_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, Stage1ZirInstIntToPtr *instruction) { - Error err; - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - // We explicitly check for the size, so we can use get_src_ptr_type - if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool has_bits; - if ((err = type_has_bits2(ira->codegen, dest_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - - if (!has_bits) { - ir_add_error(ira, dest_type_value, - buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_ptr(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_decl_ref(IrAnalyze *ira, Stage1ZirInstDeclRef *instruction) { - Stage1AirInst *ref_instruction = ir_analyze_decl_ref(ira, instruction->base.scope, instruction->base.source_node, instruction->tld); - if (type_is_invalid(ref_instruction->value->type)) { - return ira->codegen->invalid_inst_gen; - } - - if (instruction->lval == LValPtr || instruction->lval == LValAssign) { - return ref_instruction; - } else { - return ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, ref_instruction, nullptr); - } -} - -static Stage1AirInst *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, Stage1ZirInstPtrToInt *instruction) { - Error err; - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - - ZigType *src_ptr_type = get_src_ptr_type(target->value->type); - if (src_ptr_type == nullptr) { - ir_add_error(ira, target, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool has_bits; - if ((err = type_has_bits2(ira->codegen, src_ptr_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - - if (!has_bits) { - ir_add_error(ira, target, - buf_sprintf("pointer to size 0 type has no address")); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - // Since we've already run this type trough get_src_ptr_type it is - // safe to access the x_ptr fields - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, usize); - bigint_init_unsigned(&result->value->data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); - result->value->type = usize; - return result; - } else if (val->data.x_ptr.special == ConstPtrSpecialNull) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, usize); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - result->value->type = usize; - return result; - } - } - - return ir_build_ptr_to_int_gen(ira, instruction->base.scope, instruction->base.source_node, target); -} - -static Stage1AirInst *ir_analyze_instruction_ptr_type_simple(IrAnalyze *ira, - Stage1ZirInstPtrTypeSimple *instruction, bool is_const) -{ - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValuePtrTypeSimple *lazy_ptr_type = heap::c_allocator.create(); - lazy_ptr_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_ptr_type->base; - lazy_ptr_type->base.id = is_const ? LazyValueIdPtrTypeSimpleConst : LazyValueIdPtrTypeSimple; - - lazy_ptr_type->elem_type = instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_ptr_type(IrAnalyze *ira, Stage1ZirInstPtrType *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValuePtrType *lazy_ptr_type = heap::c_allocator.create(); - lazy_ptr_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_ptr_type->base; - lazy_ptr_type->base.id = LazyValueIdPtrType; - - if (instruction->sentinel != nullptr) { - if (instruction->ptr_len != PtrLenUnknown) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("sentinels are only allowed on unknown-length pointers")); - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->sentinel = instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_ptr_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->elem_type = instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - if (instruction->align_value != nullptr) { - lazy_ptr_type->align_inst = instruction->align_value->child; - if (ir_resolve_const(ira, lazy_ptr_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->ptr_len = instruction->ptr_len; - lazy_ptr_type->is_const = instruction->is_const; - lazy_ptr_type->is_volatile = instruction->is_volatile; - lazy_ptr_type->is_allowzero = instruction->is_allow_zero; - lazy_ptr_type->bit_offset_in_host = instruction->bit_offset_start; - lazy_ptr_type->host_int_bytes = instruction->host_int_bytes; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1ZirInstAlignCast *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = nullptr; - if (is_slice(target->value->type)) { - ZigType *slice_ptr_type = target->value->type->data.structure.fields[slice_ptr_index]->type_entry; - elem_type = slice_ptr_type->data.pointer.child_type; - } else if (target->value->type->id == ZigTypeIdPointer) { - elem_type = target->value->type->data.pointer.child_type; - } - - uint32_t align_bytes; - Stage1AirInst *align_bytes_inst = instruction->align_bytes->child; - if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_align_cast(ira, target, align_bytes, true); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static bool ir_resolve_addrspace(IrAnalyze *ira, Stage1AirInst *value, AddressSpace *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *addrspace_type = get_builtin_type(ira->codegen, "AddressSpace"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, addrspace_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AddressSpace)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static Stage1AirInst *ir_analyze_instruction_addrspace_cast(IrAnalyze *ira, Stage1ZirInstAddrSpaceCast *instruction) { - Stage1AirInst *ptr_inst = instruction->ptr->child; - ZigType *ptr_type = ptr_inst->value->type; - if (type_is_invalid(ptr_type)) - return ira->codegen->invalid_inst_gen; - - AddressSpace addrspace; - if (!ir_resolve_addrspace(ira, instruction->addrspace->child, &addrspace)) - return ira->codegen->invalid_inst_gen; - - if (addrspace != AddressSpaceGeneric) { - ir_add_error_node(ira, instruction->addrspace->source_node, buf_sprintf( - "address space '%s' not available in stage 1 compiler, must be .generic", - address_space_name(addrspace))); - return ira->codegen->invalid_inst_gen; - } - - if (is_slice(ptr_type) || get_src_ptr_type(ptr_type) != nullptr) { - ir_add_error_node(ira, instruction->ptr->source_node, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ptr_inst; -} - -static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) { - uint32_t align_bytes; - Stage1AirInst *align_bytes_inst = instruction->align_bytes->child; - if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes)) - return ira->codegen->invalid_inst_gen; - - if (align_bytes > 256) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("attempt to @setAlignStack(%" PRIu32 "); maximum is 256", align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - ZigFn *fn_entry = ira->fn; - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack outside function")); - return ira->codegen->invalid_inst_gen; - } - if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionNaked) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack in naked function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack in inline function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->set_alignstack_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("alignstack set twice")); - add_error_note(ira->codegen, msg, fn_entry->set_alignstack_node, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - - fn_entry->set_alignstack_node = instruction->base.source_node; - fn_entry->alignstack_value = align_bytes; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_arg_type(IrAnalyze *ira, Stage1ZirInstArgType *instruction, - bool allow_var) -{ - Stage1AirInst *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); - if (type_is_invalid(fn_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *arg_index_inst = instruction->arg_index->child; - uint64_t arg_index; - if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) - return ira->codegen->invalid_inst_gen; - - if (fn_type->id == ZigTypeIdBoundFn) { - fn_type = fn_type->data.bound_fn.fn_type; - arg_index += 1; - } - if (fn_type->id != ZigTypeIdFn) { - ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (arg_index >= fn_type_id->param_count) { - if (allow_var) { - // TODO remove this with var args - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_anytype); - } - ir_add_error(ira, arg_index_inst, - buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " argument(s)", - arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count)); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = fn_type_id->param_info[arg_index].type; - if (result_type == nullptr) { - // Args are only unresolved if our function is generic. - src_assert(fn_type->data.fn.is_generic, instruction->base.source_node); - - if (allow_var) { - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_anytype); - } else { - ir_add_error(ira, arg_index_inst, - buf_sprintf("@ArgType could not resolve the type of arg %" ZIG_PRI_u64 " because '%s' is generic", - arg_index, buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, result_type); -} - -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, Stage1AirInst *op) { - ZigType *operand_type = ir_resolve_type(ira, op); - if (type_is_invalid(operand_type)) - return ira->codegen->builtin_types.entry_invalid; - - if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { - ZigType *int_type; - if (operand_type->id == ZigTypeIdEnum) { - int_type = operand_type->data.enumeration.tag_int_type; - } else { - int_type = operand_type; - } - auto bit_count = int_type->data.integral.bit_count; - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - - if (bit_count > max_atomic_bits) { - ir_add_error(ira, op, - buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type", - max_atomic_bits, bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (operand_type->id == ZigTypeIdFloat) { - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - if (operand_type->data.floating.bit_count > max_atomic_bits) { - ir_add_error(ira, op, - buf_sprintf("expected %" PRIu32 "-bit float or smaller, found %" PRIu32 "-bit float", - max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (operand_type->id == ZigTypeIdBool) { - // will be treated as u8 - } else { - Error err; - ZigType *operand_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, operand_type, &operand_ptr_type))) - return ira->codegen->builtin_types.entry_invalid; - if (operand_ptr_type == nullptr) { - ir_add_error(ira, op, - buf_sprintf("expected bool, integer, float, enum or pointer type, found '%s'", - buf_ptr(&operand_type->name))); - return ira->codegen->builtin_types.entry_invalid; - } - } - - return operand_type; -} - -static Stage1AirInst *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, Stage1ZirInstAtomicRmw *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO let this be volatile - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicRmwOp op; - if (!ir_resolve_atomic_rmw_op(ira, instruction->op->child, &op)) { - return ira->codegen->invalid_inst_gen; - } - - if (operand_type->id == ZigTypeIdEnum && op != AtomicRmwOp_xchg) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with enum only allowed with .Xchg")); - return ira->codegen->invalid_inst_gen; - } else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with bool only allowed with .Xchg")); - return ira->codegen->invalid_inst_gen; - } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with float only allowed with .Xchg, .Add and .Sub")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_operand = ir_implicit_cast(ira, operand, operand_type); - if (type_is_invalid(casted_operand->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - if (ordering == AtomicOrderUnordered) { - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicRmw atomic ordering must not be Unordered")); - return ira->codegen->invalid_inst_gen; - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, get_the_one_possible_value(ira->codegen, operand_type)); - case OnePossibleValueNo: - break; - } - - Scope *scope = instruction->base.scope; - AstNode *source_node = instruction->base.source_node; - if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_operand, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, operand_type); - copy_const_val(ira->codegen, result->value, op1_val); - if (op == AtomicRmwOp_xchg) { - copy_const_val(ira->codegen, op1_val, op2_val); - return result; - } - - if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) { - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("TODO comptime @atomicRmw with pointers other than .Xchg")); - return ira->codegen->invalid_inst_gen; - } - - ErrorMsg *msg; - if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) { - IrBinOp bin_op; - if (op == AtomicRmwOp_min) - // store op2 if op2 < op1 - bin_op = IrBinOpCmpGreaterThan; - else - // store op2 if op2 > op1 - bin_op = IrBinOpCmpLessThan; - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, operand_type); - msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, op1_val, bin_op, op2_val, dummy_value->value); - if (msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - if (dummy_value->value->data.x_bool) - copy_const_val(ira->codegen, op1_val, op2_val); - } else { - IrBinOp bin_op; - switch (op) { - case AtomicRmwOp_xchg: - case AtomicRmwOp_max: - case AtomicRmwOp_min: - zig_unreachable(); - case AtomicRmwOp_add: - if (operand_type->id == ZigTypeIdFloat) - bin_op = IrBinOpAdd; - else - bin_op = IrBinOpAddWrap; - break; - case AtomicRmwOp_sub: - if (operand_type->id == ZigTypeIdFloat) - bin_op = IrBinOpSub; - else - bin_op = IrBinOpSubWrap; - break; - case AtomicRmwOp_and: - case AtomicRmwOp_nand: - bin_op = IrBinOpBinAnd; - break; - case AtomicRmwOp_or: - bin_op = IrBinOpBinOr; - break; - case AtomicRmwOp_xor: - bin_op = IrBinOpBinXor; - break; - } - msg = ir_eval_math_op_scalar(ira, scope, source_node, operand_type, op1_val, bin_op, op2_val, op1_val); - if (msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - if (op == AtomicRmwOp_nand) { - bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint, - operand_type->data.integral.bit_count, operand_type->data.integral.is_signed); - } - } - return result; - } - - return ir_build_atomic_rmw_gen(ira, scope, source_node, casted_ptr, casted_operand, op, - ordering, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_atomic_load(IrAnalyze *ira, Stage1ZirInstAtomicLoad *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - - if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) { - src_assert(instruction->ordering != nullptr, instruction->base.source_node); - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(casted_ptr)) { - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, casted_ptr, nullptr); - src_assert(result->value->type != nullptr, instruction->base.source_node); - return result; - } - - return ir_build_atomic_load_gen(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, ordering, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_atomic_store(IrAnalyze *ira, Stage1ZirInstAtomicStore *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, operand_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - - if (ordering == AtomicOrderAcquire || ordering == AtomicOrderAcqRel) { - src_assert(instruction->ordering != nullptr, instruction->base.source_node); - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicStore atomic ordering must not be Acquire or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) { - Stage1AirInst *result = ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, value, false); - result->value->type = ira->codegen->builtin_types.entry_void; - return result; - } - - return ir_build_atomic_store_gen(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, casted_value, ordering); -} - -static Stage1AirInst *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, Stage1ZirInstSaveErrRetAddr *instruction) { - return ir_build_save_err_ret_addr_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_node, BuiltinFnId fop, ZigType *float_type, - ZigValue *op, ZigValue *out_val) -{ - assert(ira && source_node && float_type && out_val && op); - assert(float_type->id == ZigTypeIdFloat || - float_type->id == ZigTypeIdComptimeFloat); - - unsigned bits; - - switch (float_type->id) { - case ZigTypeIdComptimeFloat: - bits = 128; - break; - case ZigTypeIdFloat: - bits = float_type->data.floating.bit_count; - break; - default: - zig_unreachable(); - } - - switch (bits) { - case 16: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f16 = f16_sqrt(op->data.x_f16); - break; - case BuiltinFnIdSin: - out_val->data.x_f16 = zig_double_to_f16(sin(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdCos: - out_val->data.x_f16 = zig_double_to_f16(cos(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdTan: - out_val->data.x_f16 = zig_double_to_f16(tan(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdExp: - out_val->data.x_f16 = zig_double_to_f16(exp(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdExp2: - out_val->data.x_f16 = zig_double_to_f16(exp2(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog: - out_val->data.x_f16 = zig_double_to_f16(log(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog10: - out_val->data.x_f16 = zig_double_to_f16(log10(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog2: - out_val->data.x_f16 = zig_double_to_f16(log2(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdFabs: - out_val->data.x_f16 = zig_double_to_f16(fabs(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdFloor: - out_val->data.x_f16 = zig_double_to_f16(floor(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdCeil: - out_val->data.x_f16 = zig_double_to_f16(ceil(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f16 = zig_double_to_f16(trunc(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f16 = zig_double_to_f16(nearbyint(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdRound: - out_val->data.x_f16 = zig_double_to_f16(round(zig_f16_to_double(op->data.x_f16))); - break; - default: - zig_unreachable(); - }; - break; - } - case 32: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f32 = sqrtf(op->data.x_f32); - break; - case BuiltinFnIdSin: - out_val->data.x_f32 = sinf(op->data.x_f32); - break; - case BuiltinFnIdCos: - out_val->data.x_f32 = cosf(op->data.x_f32); - break; - case BuiltinFnIdTan: - out_val->data.x_f32 = tanf(op->data.x_f32); - break; - case BuiltinFnIdExp: - out_val->data.x_f32 = expf(op->data.x_f32); - break; - case BuiltinFnIdExp2: - out_val->data.x_f32 = exp2f(op->data.x_f32); - break; - case BuiltinFnIdLog: - out_val->data.x_f32 = logf(op->data.x_f32); - break; - case BuiltinFnIdLog10: - out_val->data.x_f32 = log10f(op->data.x_f32); - break; - case BuiltinFnIdLog2: - out_val->data.x_f32 = log2f(op->data.x_f32); - break; - case BuiltinFnIdFabs: - out_val->data.x_f32 = fabsf(op->data.x_f32); - break; - case BuiltinFnIdFloor: - out_val->data.x_f32 = floorf(op->data.x_f32); - break; - case BuiltinFnIdCeil: - out_val->data.x_f32 = ceilf(op->data.x_f32); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f32 = truncf(op->data.x_f32); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f32 = nearbyintf(op->data.x_f32); - break; - case BuiltinFnIdRound: - out_val->data.x_f32 = roundf(op->data.x_f32); - break; - default: - zig_unreachable(); - }; - break; - } - case 64: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f64 = sqrt(op->data.x_f64); - break; - case BuiltinFnIdSin: - out_val->data.x_f64 = sin(op->data.x_f64); - break; - case BuiltinFnIdCos: - out_val->data.x_f64 = cos(op->data.x_f64); - break; - case BuiltinFnIdTan: - out_val->data.x_f64 = tan(op->data.x_f64); - break; - case BuiltinFnIdExp: - out_val->data.x_f64 = exp(op->data.x_f64); - break; - case BuiltinFnIdExp2: - out_val->data.x_f64 = exp2(op->data.x_f64); - break; - case BuiltinFnIdLog: - out_val->data.x_f64 = log(op->data.x_f64); - break; - case BuiltinFnIdLog10: - out_val->data.x_f64 = log10(op->data.x_f64); - break; - case BuiltinFnIdLog2: - out_val->data.x_f64 = log2(op->data.x_f64); - break; - case BuiltinFnIdFabs: - out_val->data.x_f64 = fabs(op->data.x_f64); - break; - case BuiltinFnIdFloor: - out_val->data.x_f64 = floor(op->data.x_f64); - break; - case BuiltinFnIdCeil: - out_val->data.x_f64 = ceil(op->data.x_f64); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f64 = trunc(op->data.x_f64); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f64 = nearbyint(op->data.x_f64); - break; - case BuiltinFnIdRound: - out_val->data.x_f64 = round(op->data.x_f64); - break; - default: - zig_unreachable(); - } - break; - } - case 80: { - extFloat80_t *out = &out_val->data.x_f80; - extFloat80_t *in = &op->data.x_f80; - switch (fop) { - case BuiltinFnIdSqrt: - extF80M_sqrt(in, out); - break; - case BuiltinFnIdFabs: - extF80M_abs(in, out); - break; - case BuiltinFnIdFloor: - extF80M_roundToInt(in, softfloat_round_min, false, out); - break; - case BuiltinFnIdCeil: - extF80M_roundToInt(in, softfloat_round_max, false, out); - break; - case BuiltinFnIdTrunc: - extF80M_trunc(in, out); - break; - case BuiltinFnIdRound: - extF80M_roundToInt(in, softfloat_round_near_maxMag, false, out); - break; - case BuiltinFnIdNearbyInt: - case BuiltinFnIdSin: - case BuiltinFnIdCos: - case BuiltinFnIdTan: - case BuiltinFnIdExp: - case BuiltinFnIdExp2: - case BuiltinFnIdLog: - case BuiltinFnIdLog10: - case BuiltinFnIdLog2: - return ir_add_error_node(ira, source_node, - buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", - float_un_op_to_name(fop), buf_ptr(&float_type->name))); - default: - zig_unreachable(); - } - break; - } - case 128: { - float128_t *out, *in; - if (float_type->id == ZigTypeIdComptimeFloat) { - out = &out_val->data.x_bigfloat.value; - in = &op->data.x_bigfloat.value; - } else { - out = &out_val->data.x_f128; - in = &op->data.x_f128; - } - switch (fop) { - case BuiltinFnIdSqrt: - f128M_sqrt(in, out); - break; - case BuiltinFnIdFabs: - f128M_abs(in, out); - break; - case BuiltinFnIdFloor: - f128M_roundToInt(in, softfloat_round_min, false, out); - break; - case BuiltinFnIdCeil: - f128M_roundToInt(in, softfloat_round_max, false, out); - break; - case BuiltinFnIdTrunc: - f128M_trunc(in, out); - break; - case BuiltinFnIdRound: - f128M_roundToInt(in, softfloat_round_near_maxMag, false, out); - break; - case BuiltinFnIdNearbyInt: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = nearbyint(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdSin: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = sin(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdCos: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = cos(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdTan: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = tan(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdExp: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = exp(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdExp2: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = exp2(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog10: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log10(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog2: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log2(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - default: - zig_unreachable(); - } - break; - } - default: - zig_unreachable(); - } - out_val->special = ConstValSpecialStatic; - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_float_op(IrAnalyze *ira, Stage1ZirInstFloatOp *instruction) { - Stage1AirInst *operand = instruction->operand->child; - ZigType *operand_type = operand->value->type; - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - // This instruction accepts floats and vectors of floats. - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - if (scalar_type->id != ZigTypeIdFloat && scalar_type->id != ZigTypeIdComptimeFloat) { - ir_add_error(ira, operand, - buf_sprintf("expected float type, found '%s'", buf_ptr(&scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(operand)) { - ZigValue *operand_val = ir_resolve_const(ira, operand, UndefOk); - if (operand_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (operand_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, operand_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, operand_type); - ZigValue *out_val = result->value; - - if (operand_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, operand_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = operand_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *elem_operand = &operand_val->data.x_array.data.s_none.elements[i]; - ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; - src_assert(elem_operand->type == scalar_type, instruction->base.source_node); - src_assert(float_out_val->type == scalar_type, instruction->base.source_node); - ErrorMsg *msg = ir_eval_float_op(ira, instruction->base.scope, instruction->base.source_node, instruction->fn_id, scalar_type, - elem_operand, float_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, instruction->base.source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - float_out_val->type = scalar_type; - } - out_val->type = operand_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_float_op(ira, instruction->base.scope, instruction->base.source_node, instruction->fn_id, scalar_type, - operand_val, out_val) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result; - } - - src_assert(scalar_type->id == ZigTypeIdFloat, instruction->base.source_node); - - return ir_build_float_op_gen(ira, instruction->base.scope, instruction->base.source_node, operand, instruction->fn_id, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_bswap(IrAnalyze *ira, Stage1ZirInstBswap *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 8 || int_type->data.integral.bit_count == 0) - return op; - - if (int_type->data.integral.bit_count % 8 != 0) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@byteSwap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", - buf_ptr(&int_type->name), int_type->data.integral.bit_count)); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, op_type); - const size_t buf_size = int_type->data.integral.bit_count / 8; - uint8_t *buf = heap::c_allocator.allocate_nonzero(buf_size); - if (is_vector) { - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(op_type->data.vector.len); - for (unsigned i = 0; i < op_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = int_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - - bigint_write_twos_complement(&op_elem_val->data.x_bigint, buf, int_type->data.integral.bit_count, true); - bigint_read_twos_complement(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, - buf, int_type->data.integral.bit_count, false, - int_type->data.integral.is_signed); - } - } else { - bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); - bigint_read_twos_complement(&result->value->data.x_bigint, buf, int_type->data.integral.bit_count, false, - int_type->data.integral.is_signed); - } - heap::c_allocator.deallocate(buf, buf_size); - return result; - } - - return ir_build_bswap_gen(ira, instruction->base.scope, instruction->base.source_node, op_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, Stage1ZirInstBitReverse *instruction) { - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, int_type); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - return result; - } - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, int_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, int_type); - size_t num_bits = int_type->data.integral.bit_count; - size_t buf_size = (num_bits + 7) / 8; - uint8_t *comptime_buf = heap::c_allocator.allocate_nonzero(buf_size); - uint8_t *result_buf = heap::c_allocator.allocate_nonzero(buf_size); - memset(comptime_buf,0,buf_size); - memset(result_buf,0,buf_size); - - bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); - - size_t bit_i = 0; - size_t bit_rev_i = num_bits - 1; - for (; bit_i < num_bits; bit_i++, bit_rev_i--) { - if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { - result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); - } - } - - bigint_read_twos_complement(&result->value->data.x_bigint, - result_buf, - int_type->data.integral.bit_count, - ira->codegen->is_big_endian, - int_type->data.integral.is_signed); - - heap::c_allocator.deallocate(comptime_buf, buf_size); - heap::c_allocator.deallocate(result_buf, buf_size); - return result; - } - - return ir_build_bit_reverse_gen(ira, instruction->base.scope, instruction->base.source_node, int_type, op); -} - - -static Stage1AirInst *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, Stage1ZirInstEnumToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_enum_to_int(ira, instruction->base.scope, instruction->base.source_node, target); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, Stage1ZirInstIntToEnum *instruction) { - Error err; - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdEnum) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigType *tag_type = dest_type->data.enumeration.tag_int_type; - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target = ir_analyze_int_cast(ira, instruction->base.scope, - instruction->base.source_node, tag_type, instruction->dest_type->source_node, - target, instruction->target->source_node); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_enum(ira, instruction->base.scope, instruction->base.source_node, casted_target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira, Stage1ZirInstCheckRuntimeScope *instruction) { - Stage1AirInst *block_comptime_inst = instruction->scope_is_comptime->child; - bool scope_is_comptime; - if (!ir_resolve_bool(ira, block_comptime_inst, &scope_is_comptime)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *is_comptime_inst = instruction->is_comptime->child; - bool is_comptime; - if (!ir_resolve_bool(ira, is_comptime_inst, &is_comptime)) - return ira->codegen->invalid_inst_gen; - - if (!scope_is_comptime && is_comptime) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("comptime control flow inside runtime block")); - add_error_note(ira->codegen, msg, block_comptime_inst->source_node, - buf_sprintf("runtime block created here")); - return ira->codegen->invalid_inst_gen; - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_has_decl(IrAnalyze *ira, Stage1ZirInstHasDecl *instruction) { - ZigType *container_type = ir_resolve_type(ira, instruction->container->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - Buf *name = ir_resolve_str(ira, instruction->name->child); - if (name == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!is_container(container_type)) { - ir_add_error_node(ira, instruction->container->source_node, - buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ScopeDecls *container_scope = get_container_scope(container_type); - Tld *tld = find_container_decl(ira->codegen, container_scope, name); - if (tld == nullptr) - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - - if (tld->visib_mod == VisibModPrivate && tld->import != get_scope_import(instruction->base.scope)) { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, true); -} - -static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) { - ScopeDecls *scope_decls = nullptr; - while (scope != nullptr) { - if (scope->id == ScopeIdDecls) { - scope_decls = reinterpret_cast(scope); - } - scope = scope->parent; - } - TldVar *tld_var = heap::c_allocator.create(); - init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); - tld_var->base.resolution = TldResolutionInvalid; - tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, - g->invalid_inst_gen->value, &tld_var->base, g->builtin_types.entry_invalid); - scope_decls->decl_table.put(var_name, &tld_var->base); -} - -static Stage1AirInst *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, Stage1ZirInstUndeclaredIdent *instruction) { - // put a variable of same name with invalid type in global scope - // so that future references to this same name will find a variable with an invalid type - populate_invalid_variable_in_scope(ira->codegen, instruction->base.scope, - instruction->base.source_node, instruction->name); - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("use of undeclared identifier '%s'", buf_ptr(instruction->name))); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_instruction_end_expr(IrAnalyze *ira, Stage1ZirInstEndExpr *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - bool was_written = instruction->result_loc->written; - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - value->value->type, value, false, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - if (result_loc->value->type->id == ZigTypeIdUnreachable) - return result_loc; - - if (!was_written || instruction->result_loc->id == ResultLocIdPeer) { - Stage1AirInst *store_ptr = ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, result_loc, value, - instruction->result_loc->allow_write_through_const); - if (type_is_invalid(store_ptr->value->type)) { - if (instruction->result_loc->id == ResultLocIdReturn && - (value->value->type->id == ZigTypeIdErrorUnion || value->value->type->id == ZigTypeIdErrorSet) && - ira->explicit_return_type->id != ZigTypeIdErrorUnion && ira->explicit_return_type->id != ZigTypeIdErrorSet && - // Only add error note if we have a node to attach it to - ira->explicit_return_type_source_node) - { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, - ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error")); - } - return ira->codegen->invalid_inst_gen; - } - } - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer && - instruction->result_loc->id != ResultLocIdPeer) - { - if (instr_is_comptime(value)) { - result_loc->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else { - result_loc->value->special = ConstValSpecialRuntime; - } - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, Stage1ZirInstImplicitCast *instruction) { - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return operand; - - ZigType *dest_type = ir_resolve_type(ira, instruction->result_loc_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, instruction->base.scope, instruction->base.source_node, - operand, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, Stage1ZirInstBitCast *instruction) { - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return operand; - - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, - &instruction->result_loc_bit_cast->base, operand->value->type, operand, false, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - - ZigType *dest_type = ir_resolve_type(ira, - instruction->result_loc_bit_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, operand, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_union_init_named_field(IrAnalyze *ira, - Stage1ZirInstUnionInitNamedField *instruction) -{ - ZigType *union_type = ir_resolve_type(ira, instruction->union_type->child); - if (type_is_invalid(union_type)) - return ira->codegen->invalid_inst_gen; - - if (union_type->id != ZigTypeIdUnion) { - ir_add_error_node(ira, instruction->union_type->source_node, - buf_sprintf("non-union type '%s' passed to @unionInit", buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); - if (field_name == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_result_loc = instruction->field_result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_union_init(ira, instruction->base.scope, instruction->base.source_node, instruction->base.source_node, - union_type, field_name, field_result_loc, result_loc); -} - -static Stage1AirInst *ir_analyze_instruction_suspend_begin(IrAnalyze *ira, Stage1ZirInstSuspendBegin *instruction) { - return ir_build_suspend_begin_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_suspend_finish(IrAnalyze *ira, Stage1ZirInstSuspendFinish *instruction) { - Stage1AirInst *begin_base = instruction->begin->base.child; - if (type_is_invalid(begin_base->value->type)) - return ira->codegen->invalid_inst_gen; - src_assert(begin_base->id == Stage1AirInstIdSuspendBegin, instruction->base.source_node); - Stage1AirInstSuspendBegin *begin = reinterpret_cast(begin_base); - - ZigFn *fn_entry = ira->fn; - src_assert(fn_entry != nullptr, instruction->base.source_node); - - if (fn_entry->inferred_async_node == nullptr) { - fn_entry->inferred_async_node = instruction->base.source_node; - } - - return ir_build_suspend_finish_gen(ira, instruction->base.scope, instruction->base.source_node, begin); -} - -static Stage1AirInst *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame_ptr, ZigFn **target_fn) -{ - if (type_is_invalid(frame_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - *target_fn = nullptr; - - ZigType *result_type; - Stage1AirInst *frame; - if (frame_ptr->value->type->id == ZigTypeIdPointer && - frame_ptr->value->type->data.pointer.ptr_len == PtrLenSingle && - frame_ptr->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigFn *func = frame_ptr->value->type->data.pointer.child_type->data.frame.fn; - result_type = func->type_entry->data.fn.fn_type_id.return_type; - *target_fn = func; - frame = frame_ptr; - } else { - frame = ir_get_deref(ira, scope, source_node, frame_ptr, nullptr); - if (frame->value->type->id == ZigTypeIdPointer && - frame->value->type->data.pointer.ptr_len == PtrLenSingle && - frame->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigFn *func = frame->value->type->data.pointer.child_type->data.frame.fn; - result_type = func->type_entry->data.fn.fn_type_id.return_type; - *target_fn = func; - } else if (frame->value->type->id != ZigTypeIdAnyFrame || - frame->value->type->data.any_frame.result_type == nullptr) - { - ir_add_error_node(ira, source_node, - buf_sprintf("expected anyframe->T, found '%s'", buf_ptr(&frame->value->type->name))); - return ira->codegen->invalid_inst_gen; - } else { - result_type = frame->value->type->data.any_frame.result_type; - } - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, result_type); - Stage1AirInst *casted_frame = ir_implicit_cast(ira, frame, any_frame_type); - if (type_is_invalid(casted_frame->value->type)) - return ira->codegen->invalid_inst_gen; - - return casted_frame; -} - -static Stage1AirInst *ir_analyze_instruction_await(IrAnalyze *ira, Stage1ZirInstAwait *instruction) { - Stage1AirInst *operand = instruction->frame->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - ZigFn *target_fn; - Stage1AirInst *frame = analyze_frame_ptr_to_anyframe_T(ira, instruction->base.scope, instruction->base.source_node, operand, &target_fn); - if (type_is_invalid(frame->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = frame->value->type->data.any_frame.result_type; - - ZigFn *fn_entry = ira->fn; - src_assert(fn_entry != nullptr, instruction->base.source_node); - - // If it's not @Frame(func) then it's definitely a suspend point - if (target_fn == nullptr && !instruction->is_nosuspend) { - if (fn_entry->inferred_async_node == nullptr) { - fn_entry->inferred_async_node = instruction->base.source_node; - } - } - - if (type_can_fail(result_type)) { - fn_entry->calls_or_awaits_errorable_fn = true; - } - - Stage1AirInst *result_loc; - if (type_has_bits(ira->codegen, result_type)) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - } else { - result_loc = nullptr; - } - - Stage1AirInstAwait *result = ir_build_await_gen(ira, instruction->base.scope, instruction->base.source_node, frame, result_type, result_loc, - instruction->is_nosuspend); - result->target_fn = target_fn; - fn_entry->await_list.append(result); - return ir_finish_anal(ira, &result->base); -} - -static Stage1AirInst *ir_analyze_instruction_resume(IrAnalyze *ira, Stage1ZirInstResume *instruction) { - Stage1AirInst *frame_ptr = instruction->frame->child; - if (type_is_invalid(frame_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *frame; - if (frame_ptr->value->type->id == ZigTypeIdPointer && - frame_ptr->value->type->data.pointer.ptr_len == PtrLenSingle && - frame_ptr->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - frame = frame_ptr; - } else { - frame = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - frame_ptr, nullptr); - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr); - Stage1AirInst *casted_frame = ir_implicit_cast2(ira, instruction->frame->scope, - instruction->frame->source_node, frame, any_frame_type); - if (type_is_invalid(casted_frame->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_resume_gen(ira, instruction->base.scope, instruction->base.source_node, casted_frame); -} - -static Stage1AirInst *ir_analyze_instruction_spill_begin(IrAnalyze *ira, Stage1ZirInstSpillBegin *instruction) { - if (ir_should_inline(ira->zir, instruction->base.scope)) - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - if (!type_has_bits(ira->codegen, operand->value->type)) - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - - switch (instruction->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: - ira->new_irb.exec->need_err_code_spill = true; - break; - } - - return ir_build_spill_begin_gen(ira, instruction->base.scope, instruction->base.source_node, operand, instruction->spill_id); -} - -static Stage1AirInst *ir_analyze_instruction_spill_end(IrAnalyze *ira, Stage1ZirInstSpillEnd *instruction) { - Stage1AirInst *operand = instruction->begin->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - if (ir_should_inline(ira->zir, instruction->base.scope) || - !type_has_bits(ira->codegen, operand->value->type) || - instr_is_comptime(operand)) - { - return operand; - } - - src_assert(instruction->begin->base.child->id == Stage1AirInstIdSpillBegin, instruction->base.source_node); - Stage1AirInstSpillBegin *begin = reinterpret_cast(instruction->begin->base.child); - - return ir_build_spill_end_gen(ira, instruction->base.scope, instruction->base.source_node, begin, operand->value->type); -} - -static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSrc *instruction) { - ZigFn *fn_entry = scope_fn_entry(instruction->base.scope); - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@src outside function")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *source_location_type = get_builtin_type(ira->codegen, "SourceLocation"); - if (type_resolve(ira->codegen, source_location_type, ResolveStatusSizeKnown)) { - zig_unreachable(); - } - - ZigValue *result = ira->codegen->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = source_location_type; - - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4); - result->data.x_struct.fields = fields; - - // file: [:0]const u8 - ensure_field_index(source_location_type, "file", 0); - fields[0]->special = ConstValSpecialStatic; - - ZigType *import = instruction->base.source_node->owner; - RootStruct *root_struct = import->data.structure.root_struct; - Buf *path = root_struct->path; - fields[0] = create_sentineled_str_lit( - ira->codegen, path, - ira->codegen->intern.for_zero_byte()); - - // fn_name: [:0]const u8 - ensure_field_index(source_location_type, "fn_name", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1] = create_sentineled_str_lit( - ira->codegen, &fn_entry->symbol_name, - ira->codegen->intern.for_zero_byte()); - - TokenLoc tok_loc = root_struct->token_locs[instruction->base.source_node->main_token]; - - // line: u32 - ensure_field_index(source_location_type, "line", 2); - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[2]->data.x_bigint, tok_loc.line + 1); - - // column: u32 - ensure_field_index(source_location_type, "column", 3); - fields[3]->special = ConstValSpecialStatic; - fields[3]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[3]->data.x_bigint, tok_loc.column + 1); - - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, result); -} - -static Stage1AirInst *ir_analyze_instruction_prefetch(IrAnalyze *ira, Stage1ZirInstPrefetch *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *raw_options_inst = instruction->options->child; - if (type_is_invalid(raw_options_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = get_builtin_type(ira->codegen, "PrefetchOptions"); - Stage1AirInst *options_inst = ir_implicit_cast(ira, raw_options_inst, options_type); - if (type_is_invalid(options_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *options_val = ir_resolve_const(ira, options_inst, UndefBad); - if (options_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *rw_val = get_const_field(ira, options_inst->source_node, options_val, "rw", 0); - if (rw_val == nullptr) - return ira->codegen->invalid_inst_gen; - PrefetchRw rw = (PrefetchRw)bigint_as_u8(&rw_val->data.x_enum_tag); - - ZigValue *locality_val = get_const_field(ira, options_inst->source_node, options_val, "locality", 1); - if (locality_val == nullptr) - return ira->codegen->invalid_inst_gen; - uint8_t locality = bigint_as_u8(&locality_val->data.x_bigint); - assert(locality <= 3); - - ZigValue *cache_val = get_const_field(ira, options_inst->source_node, options_val, "cache", 2); - if (cache_val == nullptr) - return ira->codegen->invalid_inst_gen; - PrefetchCache cache = (PrefetchCache)bigint_as_u8(&cache_val->data.x_enum_tag); - - Stage1AirInstPrefetch *air_instruction = ir_build_inst_void(&ira->new_irb, - instruction->base.scope, instruction->base.source_node); - air_instruction->ptr = ptr; - air_instruction->rw = rw; - air_instruction->locality = locality; - air_instruction->cache = cache; - - ir_ref_inst_gen(ptr); - - return &air_instruction->base; -} - -static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - - case Stage1ZirInstIdReturn: - return ir_analyze_instruction_return(ira, (Stage1ZirInstReturn *)instruction); - case Stage1ZirInstIdConst: - return ir_analyze_instruction_const(ira, (Stage1ZirInstConst *)instruction); - case Stage1ZirInstIdUnOp: - return ir_analyze_instruction_un_op(ira, (Stage1ZirInstUnOp *)instruction); - case Stage1ZirInstIdBinOp: - return ir_analyze_instruction_bin_op(ira, (Stage1ZirInstBinOp *)instruction); - case Stage1ZirInstIdMergeErrSets: - return ir_analyze_instruction_merge_err_sets(ira, (Stage1ZirInstMergeErrSets *)instruction); - case Stage1ZirInstIdDeclVar: - return ir_analyze_instruction_decl_var(ira, (Stage1ZirInstDeclVar *)instruction); - case Stage1ZirInstIdLoadPtr: - return ir_analyze_instruction_load_ptr(ira, (Stage1ZirInstLoadPtr *)instruction); - case Stage1ZirInstIdStorePtr: - return ir_analyze_instruction_store_ptr(ira, (Stage1ZirInstStorePtr *)instruction); - case Stage1ZirInstIdElemPtr: - return ir_analyze_instruction_elem_ptr(ira, (Stage1ZirInstElemPtr *)instruction); - case Stage1ZirInstIdVarPtr: - return ir_analyze_instruction_var_ptr(ira, (Stage1ZirInstVarPtr *)instruction); - case Stage1ZirInstIdFieldPtr: - return ir_analyze_instruction_field_ptr(ira, (Stage1ZirInstFieldPtr *)instruction); - case Stage1ZirInstIdCall: - return ir_analyze_instruction_call(ira, (Stage1ZirInstCall *)instruction); - case Stage1ZirInstIdCallArgs: - return ir_analyze_instruction_call_args(ira, (Stage1ZirInstCallArgs *)instruction); - case Stage1ZirInstIdCallExtra: - return ir_analyze_instruction_call_extra(ira, (Stage1ZirInstCallExtra *)instruction); - case Stage1ZirInstIdAsyncCallExtra: - return ir_analyze_instruction_async_call_extra(ira, (Stage1ZirInstAsyncCallExtra *)instruction); - case Stage1ZirInstIdBr: - return ir_analyze_instruction_br(ira, (Stage1ZirInstBr *)instruction); - case Stage1ZirInstIdCondBr: - return ir_analyze_instruction_cond_br(ira, (Stage1ZirInstCondBr *)instruction); - case Stage1ZirInstIdUnreachable: - return ir_analyze_instruction_unreachable(ira, (Stage1ZirInstUnreachable *)instruction); - case Stage1ZirInstIdPhi: - return ir_analyze_instruction_phi(ira, (Stage1ZirInstPhi *)instruction); - case Stage1ZirInstIdTypeOf: - return ir_analyze_instruction_typeof(ira, (Stage1ZirInstTypeOf *)instruction); - case Stage1ZirInstIdSetCold: - return ir_analyze_instruction_set_cold(ira, (Stage1ZirInstSetCold *)instruction); - case Stage1ZirInstIdSetRuntimeSafety: - return ir_analyze_instruction_set_runtime_safety(ira, (Stage1ZirInstSetRuntimeSafety *)instruction); - case Stage1ZirInstIdSetFloatMode: - return ir_analyze_instruction_set_float_mode(ira, (Stage1ZirInstSetFloatMode *)instruction); - case Stage1ZirInstIdAnyFrameType: - return ir_analyze_instruction_any_frame_type(ira, (Stage1ZirInstAnyFrameType *)instruction); - case Stage1ZirInstIdSliceType: - return ir_analyze_instruction_slice_type(ira, (Stage1ZirInstSliceType *)instruction); - case Stage1ZirInstIdAsm: - return ir_analyze_instruction_asm(ira, (Stage1ZirInstAsm *)instruction); - case Stage1ZirInstIdArrayType: - return ir_analyze_instruction_array_type(ira, (Stage1ZirInstArrayType *)instruction); - case Stage1ZirInstIdSizeOf: - return ir_analyze_instruction_size_of(ira, (Stage1ZirInstSizeOf *)instruction); - case Stage1ZirInstIdTestNonNull: - return ir_analyze_instruction_test_non_null(ira, (Stage1ZirInstTestNonNull *)instruction); - case Stage1ZirInstIdOptionalUnwrapPtr: - return ir_analyze_instruction_optional_unwrap_ptr(ira, (Stage1ZirInstOptionalUnwrapPtr *)instruction); - case Stage1ZirInstIdClz: - return ir_analyze_instruction_clz(ira, (Stage1ZirInstClz *)instruction); - case Stage1ZirInstIdCtz: - return ir_analyze_instruction_ctz(ira, (Stage1ZirInstCtz *)instruction); - case Stage1ZirInstIdPopCount: - return ir_analyze_instruction_pop_count(ira, (Stage1ZirInstPopCount *)instruction); - case Stage1ZirInstIdBswap: - return ir_analyze_instruction_bswap(ira, (Stage1ZirInstBswap *)instruction); - case Stage1ZirInstIdBitReverse: - return ir_analyze_instruction_bit_reverse(ira, (Stage1ZirInstBitReverse *)instruction); - case Stage1ZirInstIdSwitchBr: - return ir_analyze_instruction_switch_br(ira, (Stage1ZirInstSwitchBr *)instruction); - case Stage1ZirInstIdSwitchTarget: - return ir_analyze_instruction_switch_target(ira, (Stage1ZirInstSwitchTarget *)instruction); - case Stage1ZirInstIdSwitchVar: - return ir_analyze_instruction_switch_var(ira, (Stage1ZirInstSwitchVar *)instruction); - case Stage1ZirInstIdSwitchElseVar: - return ir_analyze_instruction_switch_else_var(ira, (Stage1ZirInstSwitchElseVar *)instruction); - case Stage1ZirInstIdImport: - return ir_analyze_instruction_import(ira, (Stage1ZirInstImport *)instruction); - case Stage1ZirInstIdRef: - return ir_analyze_instruction_ref(ira, (Stage1ZirInstRef *)instruction); - case Stage1ZirInstIdContainerInitList: - return ir_analyze_instruction_container_init_list(ira, (Stage1ZirInstContainerInitList *)instruction); - case Stage1ZirInstIdContainerInitFields: - return ir_analyze_instruction_container_init_fields(ira, (Stage1ZirInstContainerInitFields *)instruction); - case Stage1ZirInstIdCompileErr: - return ir_analyze_instruction_compile_err(ira, (Stage1ZirInstCompileErr *)instruction); - case Stage1ZirInstIdCompileLog: - return ir_analyze_instruction_compile_log(ira, (Stage1ZirInstCompileLog *)instruction); - case Stage1ZirInstIdErrName: - return ir_analyze_instruction_err_name(ira, (Stage1ZirInstErrName *)instruction); - case Stage1ZirInstIdTypeName: - return ir_analyze_instruction_type_name(ira, (Stage1ZirInstTypeName *)instruction); - case Stage1ZirInstIdCImport: - return ir_analyze_instruction_c_import(ira, (Stage1ZirInstCImport *)instruction); - case Stage1ZirInstIdCInclude: - return ir_analyze_instruction_c_include(ira, (Stage1ZirInstCInclude *)instruction); - case Stage1ZirInstIdCDefine: - return ir_analyze_instruction_c_define(ira, (Stage1ZirInstCDefine *)instruction); - case Stage1ZirInstIdCUndef: - return ir_analyze_instruction_c_undef(ira, (Stage1ZirInstCUndef *)instruction); - case Stage1ZirInstIdEmbedFile: - return ir_analyze_instruction_embed_file(ira, (Stage1ZirInstEmbedFile *)instruction); - case Stage1ZirInstIdCmpxchg: - return ir_analyze_instruction_cmpxchg(ira, (Stage1ZirInstCmpxchg *)instruction); - case Stage1ZirInstIdFence: - return ir_analyze_instruction_fence(ira, (Stage1ZirInstFence *)instruction); - case Stage1ZirInstIdReduce: - return ir_analyze_instruction_reduce(ira, (Stage1ZirInstReduce *)instruction); - case Stage1ZirInstIdTruncate: - return ir_analyze_instruction_truncate(ira, (Stage1ZirInstTruncate *)instruction); - case Stage1ZirInstIdIntCast: - return ir_analyze_instruction_int_cast(ira, (Stage1ZirInstIntCast *)instruction); - case Stage1ZirInstIdFloatCast: - return ir_analyze_instruction_float_cast(ira, (Stage1ZirInstFloatCast *)instruction); - case Stage1ZirInstIdErrSetCast: - return ir_analyze_instruction_err_set_cast(ira, (Stage1ZirInstErrSetCast *)instruction); - case Stage1ZirInstIdIntToFloat: - return ir_analyze_instruction_int_to_float(ira, (Stage1ZirInstIntToFloat *)instruction); - case Stage1ZirInstIdFloatToInt: - return ir_analyze_instruction_float_to_int(ira, (Stage1ZirInstFloatToInt *)instruction); - case Stage1ZirInstIdBoolToInt: - return ir_analyze_instruction_bool_to_int(ira, (Stage1ZirInstBoolToInt *)instruction); - case Stage1ZirInstIdVectorType: - return ir_analyze_instruction_vector_type(ira, (Stage1ZirInstVectorType *)instruction); - case Stage1ZirInstIdShuffleVector: - return ir_analyze_instruction_shuffle_vector(ira, (Stage1ZirInstShuffleVector *)instruction); - case Stage1ZirInstIdSelect: - return ir_analyze_instruction_select(ira, (Stage1ZirInstSelect *)instruction); - case Stage1ZirInstIdSplat: - return ir_analyze_instruction_splat(ira, (Stage1ZirInstSplat *)instruction); - case Stage1ZirInstIdBoolNot: - return ir_analyze_instruction_bool_not(ira, (Stage1ZirInstBoolNot *)instruction); - case Stage1ZirInstIdMemset: - return ir_analyze_instruction_memset(ira, (Stage1ZirInstMemset *)instruction); - case Stage1ZirInstIdMemcpy: - return ir_analyze_instruction_memcpy(ira, (Stage1ZirInstMemcpy *)instruction); - case Stage1ZirInstIdSlice: - return ir_analyze_instruction_slice(ira, (Stage1ZirInstSlice *)instruction); - case Stage1ZirInstIdBreakpoint: - return ir_analyze_instruction_breakpoint(ira, (Stage1ZirInstBreakpoint *)instruction); - case Stage1ZirInstIdReturnAddress: - return ir_analyze_instruction_return_address(ira, (Stage1ZirInstReturnAddress *)instruction); - case Stage1ZirInstIdFrameAddress: - return ir_analyze_instruction_frame_address(ira, (Stage1ZirInstFrameAddress *)instruction); - case Stage1ZirInstIdFrameHandle: - return ir_analyze_instruction_frame_handle(ira, (Stage1ZirInstFrameHandle *)instruction); - case Stage1ZirInstIdFrameType: - return ir_analyze_instruction_frame_type(ira, (Stage1ZirInstFrameType *)instruction); - case Stage1ZirInstIdFrameSize: - return ir_analyze_instruction_frame_size(ira, (Stage1ZirInstFrameSize *)instruction); - case Stage1ZirInstIdAlignOf: - return ir_analyze_instruction_align_of(ira, (Stage1ZirInstAlignOf *)instruction); - case Stage1ZirInstIdOverflowOp: - return ir_analyze_instruction_overflow_op(ira, (Stage1ZirInstOverflowOp *)instruction); - case Stage1ZirInstIdTestErr: - return ir_analyze_instruction_test_err(ira, (Stage1ZirInstTestErr *)instruction); - case Stage1ZirInstIdUnwrapErrCode: - return ir_analyze_instruction_unwrap_err_code(ira, (Stage1ZirInstUnwrapErrCode *)instruction); - case Stage1ZirInstIdUnwrapErrPayload: - return ir_analyze_instruction_unwrap_err_payload(ira, (Stage1ZirInstUnwrapErrPayload *)instruction); - case Stage1ZirInstIdFnProto: - return ir_analyze_instruction_fn_proto(ira, (Stage1ZirInstFnProto *)instruction); - case Stage1ZirInstIdTestComptime: - return ir_analyze_instruction_test_comptime(ira, (Stage1ZirInstTestComptime *)instruction); - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - return ir_analyze_instruction_check_switch_prongs(ira, (Stage1ZirInstCheckSwitchProngs *)instruction, false); - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return ir_analyze_instruction_check_switch_prongs(ira, (Stage1ZirInstCheckSwitchProngs *)instruction, true); - case Stage1ZirInstIdCheckStatementIsVoid: - return ir_analyze_instruction_check_statement_is_void(ira, (Stage1ZirInstCheckStatementIsVoid *)instruction); - case Stage1ZirInstIdDeclRef: - return ir_analyze_instruction_decl_ref(ira, (Stage1ZirInstDeclRef *)instruction); - case Stage1ZirInstIdPanic: - return ir_analyze_instruction_panic(ira, (Stage1ZirInstPanic *)instruction); - case Stage1ZirInstIdPtrCast: - return ir_analyze_instruction_ptr_cast(ira, (Stage1ZirInstPtrCast *)instruction); - case Stage1ZirInstIdIntToPtr: - return ir_analyze_instruction_int_to_ptr(ira, (Stage1ZirInstIntToPtr *)instruction); - case Stage1ZirInstIdPtrToInt: - return ir_analyze_instruction_ptr_to_int(ira, (Stage1ZirInstPtrToInt *)instruction); - case Stage1ZirInstIdTagName: - return ir_analyze_instruction_enum_tag_name(ira, (Stage1ZirInstTagName *)instruction); - case Stage1ZirInstIdFieldParentPtr: - return ir_analyze_instruction_field_parent_ptr(ira, (Stage1ZirInstFieldParentPtr *)instruction); - case Stage1ZirInstIdOffsetOf: - return ir_analyze_instruction_offset_of(ira, (Stage1ZirInstOffsetOf *)instruction); - case Stage1ZirInstIdBitOffsetOf: - return ir_analyze_instruction_bit_offset_of(ira, (Stage1ZirInstBitOffsetOf *)instruction); - case Stage1ZirInstIdTypeInfo: - return ir_analyze_instruction_type_info(ira, (Stage1ZirInstTypeInfo *) instruction); - case Stage1ZirInstIdType: - return ir_analyze_instruction_type(ira, (Stage1ZirInstType *)instruction); - case Stage1ZirInstIdHasField: - return ir_analyze_instruction_has_field(ira, (Stage1ZirInstHasField *) instruction); - case Stage1ZirInstIdSetEvalBranchQuota: - return ir_analyze_instruction_set_eval_branch_quota(ira, (Stage1ZirInstSetEvalBranchQuota *)instruction); - case Stage1ZirInstIdPtrType: - return ir_analyze_instruction_ptr_type(ira, (Stage1ZirInstPtrType *)instruction); - case Stage1ZirInstIdPtrTypeSimple: - return ir_analyze_instruction_ptr_type_simple(ira, (Stage1ZirInstPtrTypeSimple *)instruction, false); - case Stage1ZirInstIdPtrTypeSimpleConst: - return ir_analyze_instruction_ptr_type_simple(ira, (Stage1ZirInstPtrTypeSimple *)instruction, true); - case Stage1ZirInstIdAlignCast: - return ir_analyze_instruction_align_cast(ira, (Stage1ZirInstAlignCast *)instruction); - case Stage1ZirInstIdImplicitCast: - return ir_analyze_instruction_implicit_cast(ira, (Stage1ZirInstImplicitCast *)instruction); - case Stage1ZirInstIdResolveResult: - return ir_analyze_instruction_resolve_result(ira, (Stage1ZirInstResolveResult *)instruction); - case Stage1ZirInstIdResetResult: - return ir_analyze_instruction_reset_result(ira, (Stage1ZirInstResetResult *)instruction); - case Stage1ZirInstIdSetAlignStack: - return ir_analyze_instruction_set_align_stack(ira, (Stage1ZirInstSetAlignStack *)instruction); - case Stage1ZirInstIdArgTypeAllowVarFalse: - return ir_analyze_instruction_arg_type(ira, (Stage1ZirInstArgType *)instruction, false); - case Stage1ZirInstIdArgTypeAllowVarTrue: - return ir_analyze_instruction_arg_type(ira, (Stage1ZirInstArgType *)instruction, true); - case Stage1ZirInstIdExport: - return ir_analyze_instruction_export(ira, (Stage1ZirInstExport *)instruction); - case Stage1ZirInstIdExtern: - return ir_analyze_instruction_extern(ira, (Stage1ZirInstExtern *)instruction); - case Stage1ZirInstIdErrorReturnTrace: - return ir_analyze_instruction_error_return_trace(ira, (Stage1ZirInstErrorReturnTrace *)instruction); - case Stage1ZirInstIdErrorUnion: - return ir_analyze_instruction_error_union(ira, (Stage1ZirInstErrorUnion *)instruction); - case Stage1ZirInstIdAtomicRmw: - return ir_analyze_instruction_atomic_rmw(ira, (Stage1ZirInstAtomicRmw *)instruction); - case Stage1ZirInstIdAtomicLoad: - return ir_analyze_instruction_atomic_load(ira, (Stage1ZirInstAtomicLoad *)instruction); - case Stage1ZirInstIdAtomicStore: - return ir_analyze_instruction_atomic_store(ira, (Stage1ZirInstAtomicStore *)instruction); - case Stage1ZirInstIdSaveErrRetAddr: - return ir_analyze_instruction_save_err_ret_addr(ira, (Stage1ZirInstSaveErrRetAddr *)instruction); - case Stage1ZirInstIdAddImplicitReturnType: - return ir_analyze_instruction_add_implicit_return_type(ira, (Stage1ZirInstAddImplicitReturnType *)instruction); - case Stage1ZirInstIdFloatOp: - return ir_analyze_instruction_float_op(ira, (Stage1ZirInstFloatOp *)instruction); - case Stage1ZirInstIdMulAdd: - return ir_analyze_instruction_mul_add(ira, (Stage1ZirInstMulAdd *)instruction); - case Stage1ZirInstIdIntToErr: - return ir_analyze_instruction_int_to_err(ira, (Stage1ZirInstIntToErr *)instruction); - case Stage1ZirInstIdErrToInt: - return ir_analyze_instruction_err_to_int(ira, (Stage1ZirInstErrToInt *)instruction); - case Stage1ZirInstIdIntToEnum: - return ir_analyze_instruction_int_to_enum(ira, (Stage1ZirInstIntToEnum *)instruction); - case Stage1ZirInstIdEnumToInt: - return ir_analyze_instruction_enum_to_int(ira, (Stage1ZirInstEnumToInt *)instruction); - case Stage1ZirInstIdCheckRuntimeScope: - return ir_analyze_instruction_check_runtime_scope(ira, (Stage1ZirInstCheckRuntimeScope *)instruction); - case Stage1ZirInstIdHasDecl: - return ir_analyze_instruction_has_decl(ira, (Stage1ZirInstHasDecl *)instruction); - case Stage1ZirInstIdUndeclaredIdent: - return ir_analyze_instruction_undeclared_ident(ira, (Stage1ZirInstUndeclaredIdent *)instruction); - case Stage1ZirInstIdAlloca: - return nullptr; - case Stage1ZirInstIdEndExpr: - return ir_analyze_instruction_end_expr(ira, (Stage1ZirInstEndExpr *)instruction); - case Stage1ZirInstIdBitCast: - return ir_analyze_instruction_bit_cast_src(ira, (Stage1ZirInstBitCast *)instruction); - case Stage1ZirInstIdUnionInitNamedField: - return ir_analyze_instruction_union_init_named_field(ira, (Stage1ZirInstUnionInitNamedField *)instruction); - case Stage1ZirInstIdSuspendBegin: - return ir_analyze_instruction_suspend_begin(ira, (Stage1ZirInstSuspendBegin *)instruction); - case Stage1ZirInstIdSuspendFinish: - return ir_analyze_instruction_suspend_finish(ira, (Stage1ZirInstSuspendFinish *)instruction); - case Stage1ZirInstIdResume: - return ir_analyze_instruction_resume(ira, (Stage1ZirInstResume *)instruction); - case Stage1ZirInstIdAwait: - return ir_analyze_instruction_await(ira, (Stage1ZirInstAwait *)instruction); - case Stage1ZirInstIdSpillBegin: - return ir_analyze_instruction_spill_begin(ira, (Stage1ZirInstSpillBegin *)instruction); - case Stage1ZirInstIdSpillEnd: - return ir_analyze_instruction_spill_end(ira, (Stage1ZirInstSpillEnd *)instruction); - case Stage1ZirInstIdWasmMemorySize: - return ir_analyze_instruction_wasm_memory_size(ira, (Stage1ZirInstWasmMemorySize *)instruction); - case Stage1ZirInstIdWasmMemoryGrow: - return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction); - case Stage1ZirInstIdSrc: - return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction); - case Stage1ZirInstIdPrefetch: - return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction); - case Stage1ZirInstIdAddrSpaceCast: - return ir_analyze_instruction_addrspace_cast(ira, (Stage1ZirInstAddrSpaceCast *)instruction); - } - zig_unreachable(); -} - -// This function attempts to evaluate stage1 ZIR code while doing type checking and other analysis. -// It emits to a new Stage1Air which is partially evaluated IR code. -ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_air, - size_t *backward_branch_count, size_t *backward_branch_quota, - ZigType *expected_type, AstNode *expected_type_source_node, ZigValue *result_ptr, ZigFn *fn) -{ - assert(stage1_zir->first_err_trace_msg == nullptr); - assert(expected_type == nullptr || !type_is_invalid(expected_type)); - - IrAnalyze *ira = heap::c_allocator.create(); - ira->fn = fn; - ira->backward_branch_count = backward_branch_count; - ira->backward_branch_quota = backward_branch_quota; - ira->ref_count = 1; - ira->codegen = codegen; - - ira->explicit_return_type = expected_type; - ira->explicit_return_type_source_node = expected_type_source_node; - - ira->zir = stage1_zir; - - ira->new_irb.codegen = codegen; - ira->new_irb.exec = stage1_air; - - Stage1ZirBasicBlock *old_entry_bb = ira->zir->basic_block_list.at(0); - Stage1AirBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr); - ira->new_irb.current_basic_block = new_entry_bb; - ira->old_bb_index = 0; - - ir_start_bb(ira, old_entry_bb, nullptr); - - if (result_ptr != nullptr) { - assert(result_ptr->type->id == ZigTypeIdPointer); - Stage1AirInstConst *const_inst = ir_create_inst_noval( - &ira->new_irb, stage1_air->begin_scope, stage1_air->source_node); - const_inst->base.value = result_ptr; - ira->return_ptr = &const_inst->base; - } else { - assert(stage1_air->begin_scope != nullptr); - assert(stage1_air->source_node != nullptr); - ira->return_ptr = ir_build_return_ptr(ira, stage1_air->begin_scope, stage1_air->source_node, - get_pointer_to_type(codegen, expected_type, false)); - } - - while (ira->old_bb_index < ira->zir->basic_block_list.length) { - Stage1ZirInst *old_instruction = ira->zir_current_basic_block->instruction_list.at(ira->instruction_index); - - if (old_instruction->ref_count == 0 && !ir_inst_src_has_side_effects(old_instruction)) { - ira->instruction_index += 1; - continue; - } - - if (ira->codegen->verbose_ir) { - fprintf(stderr, "~ "); - old_instruction->src(); - fprintf(stderr, "~ "); - ir_print_inst_src(codegen, stderr, old_instruction, 0); - } - ira->suspend_source_instr = old_instruction; - Stage1AirInst *new_instruction = ir_analyze_instruction_base(ira, old_instruction); - if (new_instruction != nullptr) { - src_assert(new_instruction->value->type != nullptr || new_instruction->value->type != nullptr, old_instruction->source_node); - old_instruction->child = new_instruction; - - if (type_is_invalid(new_instruction->value->type)) { - if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> (invalid)"); - } - - if (stage1_air->first_err_trace_msg != nullptr) { - ira->codegen->trace_err = stage1_air->first_err_trace_msg; - } else { - stage1_air->first_err_trace_msg = ira->codegen->trace_err; - } - return ira->codegen->builtin_types.entry_invalid; - } else if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> "); - if (new_instruction->value->type->id == ZigTypeIdUnreachable) { - fprintf(stderr, "(noreturn)\n"); - } else { - ir_print_inst_gen(codegen, stderr, new_instruction, 0); - } - } - - // unreachable instructions do their own control flow. - if (new_instruction->value->type->id == ZigTypeIdUnreachable) - continue; - } else { - if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> (null"); - } - } - - ira->instruction_index += 1; - } - - ZigType *res_type; - if (stage1_air->first_err_trace_msg != nullptr) { - codegen->trace_err = stage1_air->first_err_trace_msg; - res_type = ira->codegen->builtin_types.entry_invalid; - } else if (ira->src_implicit_return_type_list.length == 0) { - res_type = codegen->builtin_types.entry_unreachable; - } else { - res_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, - ira->src_implicit_return_type_list.length); - } - - // It is now safe to free Pass 1 IR instructions. - ira_deref(ira); - - return res_type; -} - -bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) { - switch (instruction->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdBr: - case Stage1AirInstIdCondBr: - case Stage1AirInstIdSwitchBr: - case Stage1AirInstIdDeclVar: - case Stage1AirInstIdStorePtr: - case Stage1AirInstIdVectorStoreElem: - case Stage1AirInstIdCall: - case Stage1AirInstIdReturn: - case Stage1AirInstIdUnreachable: - case Stage1AirInstIdFence: - case Stage1AirInstIdMemset: - case Stage1AirInstIdMemcpy: - case Stage1AirInstIdBreakpoint: - case Stage1AirInstIdOverflowOp: // TODO when we support multiple returns this can be side effect free - case Stage1AirInstIdPanic: - case Stage1AirInstIdSaveErrRetAddr: - case Stage1AirInstIdAtomicRmw: - case Stage1AirInstIdAtomicStore: - case Stage1AirInstIdCmpxchg: - case Stage1AirInstIdAssertZero: - case Stage1AirInstIdAssertNonNull: - case Stage1AirInstIdPtrOfArrayToSlice: - case Stage1AirInstIdSlice: - case Stage1AirInstIdOptionalWrap: - case Stage1AirInstIdVectorToArray: - case Stage1AirInstIdSuspendBegin: - case Stage1AirInstIdSuspendFinish: - case Stage1AirInstIdResume: - case Stage1AirInstIdAwait: - case Stage1AirInstIdSpillBegin: - case Stage1AirInstIdWasmMemoryGrow: - case Stage1AirInstIdExtern: - case Stage1AirInstIdPrefetch: - return true; - - case Stage1AirInstIdPhi: - case Stage1AirInstIdBinOp: - case Stage1AirInstIdConst: - case Stage1AirInstIdCast: - case Stage1AirInstIdElemPtr: - case Stage1AirInstIdVarPtr: - case Stage1AirInstIdReturnPtr: - case Stage1AirInstIdStructFieldPtr: - case Stage1AirInstIdTestNonNull: - case Stage1AirInstIdClz: - case Stage1AirInstIdCtz: - case Stage1AirInstIdPopCount: - case Stage1AirInstIdBswap: - case Stage1AirInstIdBitReverse: - case Stage1AirInstIdUnionTag: - case Stage1AirInstIdTruncate: - case Stage1AirInstIdShuffleVector: - case Stage1AirInstIdSelect: - case Stage1AirInstIdSplat: - case Stage1AirInstIdBoolNot: - case Stage1AirInstIdReturnAddress: - case Stage1AirInstIdFrameAddress: - case Stage1AirInstIdFrameHandle: - case Stage1AirInstIdFrameSize: - case Stage1AirInstIdTestErr: - case Stage1AirInstIdPtrCast: - case Stage1AirInstIdBitCast: - case Stage1AirInstIdWidenOrShorten: - case Stage1AirInstIdPtrToInt: - case Stage1AirInstIdIntToPtr: - case Stage1AirInstIdIntToEnum: - case Stage1AirInstIdIntToErr: - case Stage1AirInstIdErrToInt: - case Stage1AirInstIdErrName: - case Stage1AirInstIdTagName: - case Stage1AirInstIdFieldParentPtr: - case Stage1AirInstIdAlignCast: - case Stage1AirInstIdErrorReturnTrace: - case Stage1AirInstIdFloatOp: - case Stage1AirInstIdMulAdd: - case Stage1AirInstIdAtomicLoad: - case Stage1AirInstIdArrayToVector: - case Stage1AirInstIdAlloca: - case Stage1AirInstIdSpillEnd: - case Stage1AirInstIdVectorExtractElem: - case Stage1AirInstIdBinaryNot: - case Stage1AirInstIdNegation: - case Stage1AirInstIdWasmMemorySize: - case Stage1AirInstIdReduce: - return false; - - case Stage1AirInstIdAsm: - { - Stage1AirInstAsm *asm_instruction = (Stage1AirInstAsm *)instruction; - return asm_instruction->has_side_effects; - } - case Stage1AirInstIdUnwrapErrPayload: - { - Stage1AirInstUnwrapErrPayload *unwrap_err_payload_instruction = - (Stage1AirInstUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on || - unwrap_err_payload_instruction->initializing; - } - case Stage1AirInstIdUnwrapErrCode: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdUnionFieldPtr: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdOptionalUnwrapPtr: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdErrWrapPayload: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdErrWrapCode: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdLoadPtr: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdRef: - return reinterpret_cast(instruction)->result_loc != nullptr; - } - zig_unreachable(); -} - -bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdBr: - case Stage1ZirInstIdCondBr: - case Stage1ZirInstIdSwitchBr: - case Stage1ZirInstIdDeclVar: - case Stage1ZirInstIdStorePtr: - case Stage1ZirInstIdCallExtra: - case Stage1ZirInstIdAsyncCallExtra: - case Stage1ZirInstIdCall: - case Stage1ZirInstIdCallArgs: - case Stage1ZirInstIdReturn: - case Stage1ZirInstIdUnreachable: - case Stage1ZirInstIdSetCold: - case Stage1ZirInstIdSetRuntimeSafety: - case Stage1ZirInstIdSetFloatMode: - case Stage1ZirInstIdImport: - case Stage1ZirInstIdCompileErr: - case Stage1ZirInstIdCompileLog: - case Stage1ZirInstIdCImport: - case Stage1ZirInstIdCInclude: - case Stage1ZirInstIdCDefine: - case Stage1ZirInstIdCUndef: - case Stage1ZirInstIdFence: - case Stage1ZirInstIdMemset: - case Stage1ZirInstIdMemcpy: - case Stage1ZirInstIdBreakpoint: - case Stage1ZirInstIdOverflowOp: // TODO when we support multiple returns this can be side effect free - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - case Stage1ZirInstIdCheckStatementIsVoid: - case Stage1ZirInstIdCheckRuntimeScope: - case Stage1ZirInstIdPanic: - case Stage1ZirInstIdSetEvalBranchQuota: - case Stage1ZirInstIdPtrType: - case Stage1ZirInstIdPtrTypeSimple: - case Stage1ZirInstIdPtrTypeSimpleConst: - case Stage1ZirInstIdSetAlignStack: - case Stage1ZirInstIdExport: - case Stage1ZirInstIdExtern: - case Stage1ZirInstIdSaveErrRetAddr: - case Stage1ZirInstIdAddImplicitReturnType: - case Stage1ZirInstIdAtomicRmw: - case Stage1ZirInstIdAtomicStore: - case Stage1ZirInstIdCmpxchg: - case Stage1ZirInstIdUndeclaredIdent: - case Stage1ZirInstIdEndExpr: - case Stage1ZirInstIdResetResult: - case Stage1ZirInstIdSuspendBegin: - case Stage1ZirInstIdSuspendFinish: - case Stage1ZirInstIdResume: - case Stage1ZirInstIdAwait: - case Stage1ZirInstIdSpillBegin: - case Stage1ZirInstIdWasmMemoryGrow: - case Stage1ZirInstIdPrefetch: - return true; - - case Stage1ZirInstIdPhi: - case Stage1ZirInstIdUnOp: - case Stage1ZirInstIdBinOp: - case Stage1ZirInstIdMergeErrSets: - case Stage1ZirInstIdLoadPtr: - case Stage1ZirInstIdConst: - case Stage1ZirInstIdContainerInitList: - case Stage1ZirInstIdContainerInitFields: - case Stage1ZirInstIdUnionInitNamedField: - case Stage1ZirInstIdFieldPtr: - case Stage1ZirInstIdElemPtr: - case Stage1ZirInstIdVarPtr: - case Stage1ZirInstIdTypeOf: - case Stage1ZirInstIdArrayType: - case Stage1ZirInstIdSliceType: - case Stage1ZirInstIdAnyFrameType: - case Stage1ZirInstIdSizeOf: - case Stage1ZirInstIdTestNonNull: - case Stage1ZirInstIdOptionalUnwrapPtr: - case Stage1ZirInstIdClz: - case Stage1ZirInstIdCtz: - case Stage1ZirInstIdPopCount: - case Stage1ZirInstIdBswap: - case Stage1ZirInstIdBitReverse: - case Stage1ZirInstIdSwitchVar: - case Stage1ZirInstIdSwitchElseVar: - case Stage1ZirInstIdSwitchTarget: - case Stage1ZirInstIdRef: - case Stage1ZirInstIdEmbedFile: - case Stage1ZirInstIdTruncate: - case Stage1ZirInstIdVectorType: - case Stage1ZirInstIdShuffleVector: - case Stage1ZirInstIdSelect: - case Stage1ZirInstIdSplat: - case Stage1ZirInstIdBoolNot: - case Stage1ZirInstIdSlice: - case Stage1ZirInstIdAlignOf: - case Stage1ZirInstIdReturnAddress: - case Stage1ZirInstIdFrameAddress: - case Stage1ZirInstIdFrameHandle: - case Stage1ZirInstIdFrameType: - case Stage1ZirInstIdFrameSize: - case Stage1ZirInstIdTestErr: - case Stage1ZirInstIdFnProto: - case Stage1ZirInstIdTestComptime: - case Stage1ZirInstIdPtrCast: - case Stage1ZirInstIdBitCast: - case Stage1ZirInstIdPtrToInt: - case Stage1ZirInstIdIntToPtr: - case Stage1ZirInstIdIntToEnum: - case Stage1ZirInstIdIntToErr: - case Stage1ZirInstIdErrToInt: - case Stage1ZirInstIdDeclRef: - case Stage1ZirInstIdErrName: - case Stage1ZirInstIdTypeName: - case Stage1ZirInstIdTagName: - case Stage1ZirInstIdFieldParentPtr: - case Stage1ZirInstIdOffsetOf: - case Stage1ZirInstIdBitOffsetOf: - case Stage1ZirInstIdTypeInfo: - case Stage1ZirInstIdType: - case Stage1ZirInstIdHasField: - case Stage1ZirInstIdAlignCast: - case Stage1ZirInstIdImplicitCast: - case Stage1ZirInstIdResolveResult: - case Stage1ZirInstIdArgTypeAllowVarFalse: - case Stage1ZirInstIdArgTypeAllowVarTrue: - case Stage1ZirInstIdErrorReturnTrace: - case Stage1ZirInstIdErrorUnion: - case Stage1ZirInstIdFloatOp: - case Stage1ZirInstIdMulAdd: - case Stage1ZirInstIdAtomicLoad: - case Stage1ZirInstIdIntCast: - case Stage1ZirInstIdFloatCast: - case Stage1ZirInstIdErrSetCast: - case Stage1ZirInstIdIntToFloat: - case Stage1ZirInstIdFloatToInt: - case Stage1ZirInstIdBoolToInt: - case Stage1ZirInstIdEnumToInt: - case Stage1ZirInstIdHasDecl: - case Stage1ZirInstIdAlloca: - case Stage1ZirInstIdSpillEnd: - case Stage1ZirInstIdWasmMemorySize: - case Stage1ZirInstIdSrc: - case Stage1ZirInstIdReduce: - case Stage1ZirInstIdAddrSpaceCast: - return false; - - case Stage1ZirInstIdAsm: - { - Stage1ZirInstAsm *asm_instruction = (Stage1ZirInstAsm *)instruction; - return asm_instruction->has_side_effects; - } - - case Stage1ZirInstIdUnwrapErrPayload: - { - Stage1ZirInstUnwrapErrPayload *unwrap_err_payload_instruction = - (Stage1ZirInstUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on || - unwrap_err_payload_instruction->initializing; - } - case Stage1ZirInstIdUnwrapErrCode: - return reinterpret_cast(instruction)->initializing; - } - zig_unreachable(); -} - -static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, LazyValueFnType *lazy_fn_type) { - Error err; - AstNode *proto_node = lazy_fn_type->proto_node; - - FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, lazy_fn_type->cc, proto_node->data.fn_proto.params.length); - - if (proto_node->data.fn_proto.callconv_expr != nullptr) { - if ((err = emit_error_unless_callconv_allowed_for_target(ira->codegen, proto_node->data.fn_proto.callconv_expr, lazy_fn_type->cc))) - return nullptr; - } - - for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) { - if (fn_type_id.cc == CallingConventionC) { - fn_type_id.param_count = fn_type_id.next_param_index; - break; - } else { - ir_add_error_node(ira, param_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return nullptr; - } - } - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - - if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) { - param_info->type = nullptr; - return get_generic_fn_type(ira->codegen, &fn_type_id); - } else { - Stage1AirInst *param_type_inst = lazy_fn_type->param_types[fn_type_id.next_param_index]; - ZigType *param_type = ir_resolve_type(ira, param_type_inst); - if (type_is_invalid(param_type)) - return nullptr; - - if(!is_valid_param_type(param_type)){ - if(param_type->id == ZigTypeIdOpaque){ - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of opaque type '%s' not allowed", buf_ptr(¶m_type->name))); - } else { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' not allowed", buf_ptr(¶m_type->name))); - } - - return nullptr; - } - - switch (type_requires_comptime(ira->codegen, param_type)) { - case ReqCompTimeYes: - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return nullptr; - } - param_info->type = param_type; - fn_type_id.next_param_index += 1; - return get_generic_fn_type(ira->codegen, &fn_type_id); - case ReqCompTimeInvalid: - return nullptr; - case ReqCompTimeNo: - break; - } - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - bool has_bits; - if ((err = type_has_bits2(ira->codegen, param_type, &has_bits))) - return nullptr; - if (!has_bits) { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return nullptr; - } - } - param_info->type = param_type; - } - } - - if (lazy_fn_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_fn_type->align_inst, nullptr, &fn_type_id.alignment)) - return nullptr; - } - - fn_type_id.return_type = ir_resolve_type(ira, lazy_fn_type->return_type); - if (type_is_invalid(fn_type_id.return_type)) - return nullptr; - if (fn_type_id.return_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, lazy_fn_type->return_type->source_node, - buf_create_from_str("return type cannot be opaque")); - return nullptr; - } - - return get_fn_type(ira->codegen, &fn_type_id); -} - -static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { - Error err; - if (val->special != ConstValSpecialLazy) - return ErrorNone; - switch (val->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - case LazyValueIdTypeInfoDecls: { - LazyValueTypeInfoDecls *type_info_decls = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = type_info_decls->ira; - - if ((err = ir_make_type_info_decls(ira, type_info_decls->source_node, val, type_info_decls->decls_scope, true))) - { - return err; - }; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdAlignOf: { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_align_of->ira; - - if (lazy_align_of->target_type->value->special == ConstValSpecialStatic) { - switch (lazy_align_of->target_type->value->data.x_type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdOpaque: - ir_add_error_node(ira, source_node, - buf_sprintf("no align available for type '%s'", - buf_ptr(&lazy_align_of->target_type->value->data.x_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - } - - uint32_t align_in_bytes; - if ((err = type_val_resolve_abi_align(ira->codegen, source_node, - lazy_align_of->target_type->value, &align_in_bytes))) - { - return err; - } - - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); - bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdSizeOf: { - LazyValueSizeOf *lazy_size_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_size_of->ira; - - if (lazy_size_of->target_type->value->special == ConstValSpecialStatic) { - switch (lazy_size_of->target_type->value->data.x_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_size_of->target_type->source_node, - buf_sprintf("no size available for type '%s'", - buf_ptr(&lazy_size_of->target_type->value->data.x_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdEnumLiteral: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - } - - size_t abi_size; - size_t size_in_bits; - if ((err = type_val_resolve_abi_size(ira->codegen, source_node, lazy_size_of->target_type->value, - &abi_size, &size_in_bits))) - { - return err; - } - - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); - if (lazy_size_of->bit_size) - bigint_init_unsigned(&val->data.x_bigint, size_in_bits); - else - bigint_init_unsigned(&val->data.x_bigint, abi_size); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_slice_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - ZigValue *sentinel_val; - if (lazy_slice_type->sentinel != nullptr) { - if (type_is_invalid(lazy_slice_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } else { - sentinel_val = nullptr; - } - - uint32_t align_bytes = 0; - if (lazy_slice_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes)) - return ErrorSemanticAnalyzeFail; - } - - switch (elem_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_slice_type->elem_type->source_node, - buf_sprintf("slice of type '%s' not allowed", buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - - ResolveStatus needed_status = (align_bytes == 0) ? - ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(ira->codegen, elem_type, needed_status))) - return err; - ZigType *slice_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - lazy_slice_type->is_const, lazy_slice_type->is_volatile, - PtrLenUnknown, - align_bytes, - 0, 0, lazy_slice_type->is_allowzero, - VECTOR_INDEX_NONE, nullptr, sentinel_val); - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - ZigValue *sentinel_val; - if (lazy_ptr_type->sentinel != nullptr) { - if (type_is_invalid(lazy_ptr_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } else { - sentinel_val = nullptr; - } - - uint32_t align_bytes = 0; - if (lazy_ptr_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes)) - return ErrorSemanticAnalyzeFail; - } - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } else if (elem_type->id == ZigTypeIdOpaque && lazy_ptr_type->ptr_len == PtrLenUnknown) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("unknown-length pointer to opaque")); - return ErrorSemanticAnalyzeFail; - } else if (lazy_ptr_type->ptr_len == PtrLenC) { - bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, elem_type, ExternPositionOther, &ok_type))) - return err; - if (!ok_type) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - } else if (elem_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers cannot point to opaque types")); - return ErrorSemanticAnalyzeFail; - } else if (lazy_ptr_type->is_allowzero) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers always allow address zero")); - return ErrorSemanticAnalyzeFail; - } - } - - if (align_bytes != 0) { - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) - return err; - if (!type_has_bits(ira->codegen, elem_type)) - align_bytes = 0; - } - bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, - lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, - allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrTypeSimple: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - false, false, PtrLenSingle, 0, - 0, 0, - false, VECTOR_INDEX_NONE, nullptr, nullptr); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - true, false, PtrLenSingle, 0, - 0, 0, - false, VECTOR_INDEX_NONE, nullptr, nullptr); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_array_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_array_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - switch (elem_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_array_type->elem_type->source_node, - buf_sprintf("array of type '%s' not allowed", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - - // Avoid resolving the type if the total length is zero. - // Matches the logic in get_array_type and in the lazy alignment - // resolution routine. - if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0) { - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return err; - } - - ZigValue *sentinel_val = nullptr; - if (lazy_array_type->sentinel != nullptr) { - if (type_is_invalid(lazy_array_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_array_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_array_type(ira->codegen, elem_type, lazy_array_type->length, sentinel_val); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdOptType: { - LazyValueOptType *lazy_opt_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_opt_type->ira; - - ZigType *payload_type = ir_resolve_type(ira, lazy_opt_type->payload_type); - if (type_is_invalid(payload_type)) - return ErrorSemanticAnalyzeFail; - - if (payload_type->id == ZigTypeIdOpaque || payload_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_opt_type->payload_type->source_node, - buf_sprintf("type '%s' cannot be optional", buf_ptr(&payload_type->name))); - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return err; - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_optional_type(ira->codegen, payload_type); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_fn_type->ira; - ZigType *fn_type = ir_resolve_lazy_fn_type(ira, source_node, lazy_fn_type); - if (fn_type == nullptr) - return ErrorSemanticAnalyzeFail; - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = fn_type; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_err_union_type->ira; - - ZigType *err_set_type = ir_resolve_type(ira, lazy_err_union_type->err_set_type); - if (type_is_invalid(err_set_type)) - return ErrorSemanticAnalyzeFail; - - ZigType *payload_type = ir_resolve_type(ira, lazy_err_union_type->payload_type); - if (type_is_invalid(payload_type)) - return ErrorSemanticAnalyzeFail; - - if (err_set_type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, lazy_err_union_type->err_set_type->source_node, - buf_sprintf("expected error set type, found type '%s'", - buf_ptr(&err_set_type->name))); - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - } - zig_unreachable(); -} - -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len) { - Error err; - switch (val->data.x_array.special) { - case ConstArraySpecialUndef: - case ConstArraySpecialBuf: - return ErrorNone; - case ConstArraySpecialNone: - break; - } - ZigValue *elems = val->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if ((err = ir_resolve_lazy_recurse(source_node, &elems[i]))) - return err; - } - - return ErrorNone; -} - -static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { - Error err; - if ((err = ir_resolve_lazy_raw(source_node, val))) - return err; - assert(val->special != ConstValSpecialRuntime); - assert(val->special != ConstValSpecialLazy); - if (val->special != ConstValSpecialStatic) - return ErrorNone; - switch (val->type->id) { - case ZigTypeIdOpaque: - case ZigTypeIdEnum: - case ZigTypeIdMetaType: - case ZigTypeIdBool: - case ZigTypeIdVoid: - case ZigTypeIdComptimeFloat: - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdErrorSet: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdAnyFrame: - case ZigTypeIdBoundFn: - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - return ErrorNone; - case ZigTypeIdFnFrame: - zig_panic("TODO: ir_resolve_lazy_recurse ZigTypeIdFnFrame"); - case ZigTypeIdUnion: { - ConstUnionValue *union_val = &val->data.x_union; - return ir_resolve_lazy_recurse(source_node, union_val->payload); - } - case ZigTypeIdVector: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.vector.len); - case ZigTypeIdArray: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.array.len); - case ZigTypeIdStruct: - for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { - ZigValue *field = val->data.x_struct.fields[i]; - if (val->type->data.structure.fields[i]->is_comptime) { - // comptime struct fields do not need to be resolved because - // they are not part of the value. - continue; - } - if ((err = ir_resolve_lazy_recurse(source_node, field))) - return err; - } - return ErrorNone; - case ZigTypeIdOptional: - if (get_src_ptr_type(val->type) != nullptr) - return ErrorNone; - if (val->data.x_optional == nullptr) - return ErrorNone; - - return ir_resolve_lazy_recurse(source_node, val->data.x_optional); - case ZigTypeIdErrorUnion: { - bool is_err = val->data.x_err_union.error_set->data.x_err_set != nullptr; - if (is_err) { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.error_set); - } else { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.payload); - } - } - } - zig_unreachable(); -} - -Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val) { - Error err; - if ((err = ir_resolve_lazy_raw(source_node, val))) { - return err; - } - if (type_is_invalid(val->type)) { - return ErrorSemanticAnalyzeFail; - } - return ErrorNone; -} - -void Stage1AirInst::src() { - Stage1AirInst *inst = this; - if (inst->source_node != nullptr) { - inst->source_node->src(); - } else { - fprintf(stderr, "(null source node)\n"); - } -} - -void Stage1AirInst::dump() { - Stage1AirInst *inst = this; - inst->src(); - if (inst->scope == nullptr) { - fprintf(stderr, "(null scope)\n"); - } else { - ir_print_inst_gen(inst->scope->codegen, stderr, inst, 0); - } -} - -void IrAnalyze::dump() { - ir_print_gen(this->codegen, stderr, this->new_irb.exec, 0); - if (this->new_irb.current_basic_block != nullptr) { - fprintf(stderr, "Current basic block:\n"); - ir_print_basic_block_gen(this->codegen, stderr, this->new_irb.current_basic_block, 1); - } -} diff --git a/src/stage1/ir.hpp b/src/stage1/ir.hpp deleted file mode 100644 index 6a998adf4022..000000000000 --- a/src/stage1/ir.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_IR_HPP -#define ZIG_IR_HPP - -#include "all_types.hpp" - -Stage1AirInst *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, - ZigType *var_type, const char *name_hint); - -Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigValue *return_ptr, size_t *backward_branch_count, size_t *backward_branch_quota, - ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - Stage1Air *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef); - -Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val); - -ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_air, - size_t *backward_branch_count, size_t *backward_branch_quota, - ZigType *expected_type, AstNode *expected_type_source_node, ZigValue *result_ptr, - ZigFn *fn); - -bool ir_inst_gen_has_side_effects(Stage1AirInst *inst); - -struct IrAnalyze; -ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val, - AstNode *source_node); - -#endif diff --git a/src/stage1/ir_print.cpp b/src/stage1/ir_print.cpp deleted file mode 100644 index c86a0b975edb..000000000000 --- a/src/stage1/ir_print.cpp +++ /dev/null @@ -1,3543 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "all_types.hpp" -#include "analyze.hpp" -#include "ir.hpp" -#include "astgen.hpp" -#include "ir_print.hpp" -#include "os.hpp" - -static uint32_t hash_inst_src_ptr(Stage1ZirInst* instruction) { - return (uint32_t)(uintptr_t)instruction; -} - -static uint32_t hash_inst_gen_ptr(Stage1AirInst* instruction) { - return (uint32_t)(uintptr_t)instruction; -} - -static bool inst_src_ptr_eql(Stage1ZirInst* a, Stage1ZirInst* b) { - return a == b; -} - -static bool inst_gen_ptr_eql(Stage1AirInst* a, Stage1AirInst* b) { - return a == b; -} - -using InstSetSrc = HashMap; -using InstSetGen = HashMap; -using InstListSrc = ZigList; -using InstListGen = ZigList; - -struct IrPrintSrc { - CodeGen *codegen; - FILE *f; - int indent; - int indent_size; -}; - -struct IrPrintGen { - CodeGen *codegen; - FILE *f; - int indent; - int indent_size; - - // When printing pass 2 instructions referenced var instructions are not - // present in the instruction list. Thus we track which instructions - // are printed (per executable) and after each pass 2 instruction those - // var instructions are rendered in a trailing fashion. - InstSetGen printed; - InstListGen pending; -}; - -static void ir_print_other_inst_src(IrPrintSrc *irp, Stage1ZirInst *inst); -static void ir_print_other_inst_gen(IrPrintGen *irp, Stage1AirInst *inst); - -static void ir_print_call_modifier(FILE *f, CallModifier modifier) { - switch (modifier) { - case CallModifierNone: - break; - case CallModifierNoSuspend: - fprintf(f, "nosuspend "); - break; - case CallModifierAsync: - fprintf(f, "async "); - break; - case CallModifierNeverTail: - fprintf(f, "notail "); - break; - case CallModifierNeverInline: - fprintf(f, "noinline "); - break; - case CallModifierAlwaysTail: - fprintf(f, "tail "); - break; - case CallModifierAlwaysInline: - fprintf(f, "inline "); - break; - case CallModifierCompileTime: - fprintf(f, "comptime "); - break; - case CallModifierBuiltin: - zig_unreachable(); - } -} - -const char* ir_inst_src_type_str(Stage1ZirInstId id) { - switch (id) { - case Stage1ZirInstIdInvalid: - return "SrcInvalid"; - case Stage1ZirInstIdShuffleVector: - return "SrcShuffle"; - case Stage1ZirInstIdSelect: - return "SrcSelect"; - case Stage1ZirInstIdSplat: - return "SrcSplat"; - case Stage1ZirInstIdDeclVar: - return "SrcDeclVar"; - case Stage1ZirInstIdBr: - return "SrcBr"; - case Stage1ZirInstIdCondBr: - return "SrcCondBr"; - case Stage1ZirInstIdSwitchBr: - return "SrcSwitchBr"; - case Stage1ZirInstIdSwitchVar: - return "SrcSwitchVar"; - case Stage1ZirInstIdSwitchElseVar: - return "SrcSwitchElseVar"; - case Stage1ZirInstIdSwitchTarget: - return "SrcSwitchTarget"; - case Stage1ZirInstIdPhi: - return "SrcPhi"; - case Stage1ZirInstIdUnOp: - return "SrcUnOp"; - case Stage1ZirInstIdBinOp: - return "SrcBinOp"; - case Stage1ZirInstIdMergeErrSets: - return "SrcMergeErrSets"; - case Stage1ZirInstIdLoadPtr: - return "SrcLoadPtr"; - case Stage1ZirInstIdStorePtr: - return "SrcStorePtr"; - case Stage1ZirInstIdFieldPtr: - return "SrcFieldPtr"; - case Stage1ZirInstIdElemPtr: - return "SrcElemPtr"; - case Stage1ZirInstIdVarPtr: - return "SrcVarPtr"; - case Stage1ZirInstIdCallExtra: - return "SrcCallExtra"; - case Stage1ZirInstIdAsyncCallExtra: - return "SrcAsyncCallExtra"; - case Stage1ZirInstIdCall: - return "SrcCall"; - case Stage1ZirInstIdCallArgs: - return "SrcCallArgs"; - case Stage1ZirInstIdConst: - return "SrcConst"; - case Stage1ZirInstIdReturn: - return "SrcReturn"; - case Stage1ZirInstIdContainerInitList: - return "SrcContainerInitList"; - case Stage1ZirInstIdContainerInitFields: - return "SrcContainerInitFields"; - case Stage1ZirInstIdUnreachable: - return "SrcUnreachable"; - case Stage1ZirInstIdTypeOf: - return "SrcTypeOf"; - case Stage1ZirInstIdSetCold: - return "SrcSetCold"; - case Stage1ZirInstIdSetRuntimeSafety: - return "SrcSetRuntimeSafety"; - case Stage1ZirInstIdSetFloatMode: - return "SrcSetFloatMode"; - case Stage1ZirInstIdArrayType: - return "SrcArrayType"; - case Stage1ZirInstIdAnyFrameType: - return "SrcAnyFrameType"; - case Stage1ZirInstIdSliceType: - return "SrcSliceType"; - case Stage1ZirInstIdAsm: - return "SrcAsm"; - case Stage1ZirInstIdSizeOf: - return "SrcSizeOf"; - case Stage1ZirInstIdTestNonNull: - return "SrcTestNonNull"; - case Stage1ZirInstIdOptionalUnwrapPtr: - return "SrcOptionalUnwrapPtr"; - case Stage1ZirInstIdClz: - return "SrcClz"; - case Stage1ZirInstIdCtz: - return "SrcCtz"; - case Stage1ZirInstIdPopCount: - return "SrcPopCount"; - case Stage1ZirInstIdBswap: - return "SrcBswap"; - case Stage1ZirInstIdBitReverse: - return "SrcBitReverse"; - case Stage1ZirInstIdImport: - return "SrcImport"; - case Stage1ZirInstIdCImport: - return "SrcCImport"; - case Stage1ZirInstIdCInclude: - return "SrcCInclude"; - case Stage1ZirInstIdCDefine: - return "SrcCDefine"; - case Stage1ZirInstIdCUndef: - return "SrcCUndef"; - case Stage1ZirInstIdRef: - return "SrcRef"; - case Stage1ZirInstIdCompileErr: - return "SrcCompileErr"; - case Stage1ZirInstIdCompileLog: - return "SrcCompileLog"; - case Stage1ZirInstIdErrName: - return "SrcErrName"; - case Stage1ZirInstIdEmbedFile: - return "SrcEmbedFile"; - case Stage1ZirInstIdCmpxchg: - return "SrcCmpxchg"; - case Stage1ZirInstIdFence: - return "SrcFence"; - case Stage1ZirInstIdReduce: - return "SrcReduce"; - case Stage1ZirInstIdTruncate: - return "SrcTruncate"; - case Stage1ZirInstIdIntCast: - return "SrcIntCast"; - case Stage1ZirInstIdFloatCast: - return "SrcFloatCast"; - case Stage1ZirInstIdIntToFloat: - return "SrcIntToFloat"; - case Stage1ZirInstIdFloatToInt: - return "SrcFloatToInt"; - case Stage1ZirInstIdBoolToInt: - return "SrcBoolToInt"; - case Stage1ZirInstIdVectorType: - return "SrcVectorType"; - case Stage1ZirInstIdBoolNot: - return "SrcBoolNot"; - case Stage1ZirInstIdMemset: - return "SrcMemset"; - case Stage1ZirInstIdMemcpy: - return "SrcMemcpy"; - case Stage1ZirInstIdSlice: - return "SrcSlice"; - case Stage1ZirInstIdBreakpoint: - return "SrcBreakpoint"; - case Stage1ZirInstIdReturnAddress: - return "SrcReturnAddress"; - case Stage1ZirInstIdFrameAddress: - return "SrcFrameAddress"; - case Stage1ZirInstIdFrameHandle: - return "SrcFrameHandle"; - case Stage1ZirInstIdFrameType: - return "SrcFrameType"; - case Stage1ZirInstIdFrameSize: - return "SrcFrameSize"; - case Stage1ZirInstIdAlignOf: - return "SrcAlignOf"; - case Stage1ZirInstIdOverflowOp: - return "SrcOverflowOp"; - case Stage1ZirInstIdTestErr: - return "SrcTestErr"; - case Stage1ZirInstIdMulAdd: - return "SrcMulAdd"; - case Stage1ZirInstIdFloatOp: - return "SrcFloatOp"; - case Stage1ZirInstIdUnwrapErrCode: - return "SrcUnwrapErrCode"; - case Stage1ZirInstIdUnwrapErrPayload: - return "SrcUnwrapErrPayload"; - case Stage1ZirInstIdFnProto: - return "SrcFnProto"; - case Stage1ZirInstIdTestComptime: - return "SrcTestComptime"; - case Stage1ZirInstIdPtrCast: - return "SrcPtrCast"; - case Stage1ZirInstIdBitCast: - return "SrcBitCast"; - case Stage1ZirInstIdIntToPtr: - return "SrcIntToPtr"; - case Stage1ZirInstIdPtrToInt: - return "SrcPtrToInt"; - case Stage1ZirInstIdIntToEnum: - return "SrcIntToEnum"; - case Stage1ZirInstIdEnumToInt: - return "SrcEnumToInt"; - case Stage1ZirInstIdIntToErr: - return "SrcIntToErr"; - case Stage1ZirInstIdErrToInt: - return "SrcErrToInt"; - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - return "SrcCheckSwitchProngsUnderNo"; - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return "SrcCheckSwitchProngsUnderYes"; - case Stage1ZirInstIdCheckStatementIsVoid: - return "SrcCheckStatementIsVoid"; - case Stage1ZirInstIdTypeName: - return "SrcTypeName"; - case Stage1ZirInstIdDeclRef: - return "SrcDeclRef"; - case Stage1ZirInstIdPanic: - return "SrcPanic"; - case Stage1ZirInstIdTagName: - return "SrcTagName"; - case Stage1ZirInstIdFieldParentPtr: - return "SrcFieldParentPtr"; - case Stage1ZirInstIdOffsetOf: - return "SrcOffsetOf"; - case Stage1ZirInstIdBitOffsetOf: - return "SrcBitOffsetOf"; - case Stage1ZirInstIdTypeInfo: - return "SrcTypeInfo"; - case Stage1ZirInstIdType: - return "SrcType"; - case Stage1ZirInstIdHasField: - return "SrcHasField"; - case Stage1ZirInstIdSetEvalBranchQuota: - return "SrcSetEvalBranchQuota"; - case Stage1ZirInstIdPtrType: - return "SrcPtrType"; - case Stage1ZirInstIdPtrTypeSimple: - return "SrcPtrTypeSimple"; - case Stage1ZirInstIdPtrTypeSimpleConst: - return "SrcPtrTypeSimpleConst"; - case Stage1ZirInstIdAlignCast: - return "SrcAlignCast"; - case Stage1ZirInstIdImplicitCast: - return "SrcImplicitCast"; - case Stage1ZirInstIdResolveResult: - return "SrcResolveResult"; - case Stage1ZirInstIdResetResult: - return "SrcResetResult"; - case Stage1ZirInstIdSetAlignStack: - return "SrcSetAlignStack"; - case Stage1ZirInstIdArgTypeAllowVarFalse: - return "SrcArgTypeAllowVarFalse"; - case Stage1ZirInstIdArgTypeAllowVarTrue: - return "SrcArgTypeAllowVarTrue"; - case Stage1ZirInstIdExport: - return "SrcExport"; - case Stage1ZirInstIdExtern: - return "SrcExtern"; - case Stage1ZirInstIdErrorReturnTrace: - return "SrcErrorReturnTrace"; - case Stage1ZirInstIdErrorUnion: - return "SrcErrorUnion"; - case Stage1ZirInstIdAtomicRmw: - return "SrcAtomicRmw"; - case Stage1ZirInstIdAtomicLoad: - return "SrcAtomicLoad"; - case Stage1ZirInstIdAtomicStore: - return "SrcAtomicStore"; - case Stage1ZirInstIdSaveErrRetAddr: - return "SrcSaveErrRetAddr"; - case Stage1ZirInstIdAddImplicitReturnType: - return "SrcAddImplicitReturnType"; - case Stage1ZirInstIdErrSetCast: - return "SrcErrSetCast"; - case Stage1ZirInstIdCheckRuntimeScope: - return "SrcCheckRuntimeScope"; - case Stage1ZirInstIdHasDecl: - return "SrcHasDecl"; - case Stage1ZirInstIdUndeclaredIdent: - return "SrcUndeclaredIdent"; - case Stage1ZirInstIdAlloca: - return "SrcAlloca"; - case Stage1ZirInstIdEndExpr: - return "SrcEndExpr"; - case Stage1ZirInstIdUnionInitNamedField: - return "SrcUnionInitNamedField"; - case Stage1ZirInstIdSuspendBegin: - return "SrcSuspendBegin"; - case Stage1ZirInstIdSuspendFinish: - return "SrcSuspendFinish"; - case Stage1ZirInstIdAwait: - return "SrcAwaitSr"; - case Stage1ZirInstIdResume: - return "SrcResume"; - case Stage1ZirInstIdSpillBegin: - return "SrcSpillBegin"; - case Stage1ZirInstIdSpillEnd: - return "SrcSpillEnd"; - case Stage1ZirInstIdWasmMemorySize: - return "SrcWasmMemorySize"; - case Stage1ZirInstIdWasmMemoryGrow: - return "SrcWasmMemoryGrow"; - case Stage1ZirInstIdSrc: - return "SrcSrc"; - case Stage1ZirInstIdPrefetch: - return "SrcPrefetch"; - case Stage1ZirInstIdAddrSpaceCast: - return "SrcAddrSpaceCast"; - } - zig_unreachable(); -} - -const char* ir_inst_gen_type_str(Stage1AirInstId id) { - switch (id) { - case Stage1AirInstIdInvalid: - return "GenInvalid"; - case Stage1AirInstIdShuffleVector: - return "GenShuffle"; - case Stage1AirInstIdSelect: - return "GenSelect"; - case Stage1AirInstIdSplat: - return "GenSplat"; - case Stage1AirInstIdDeclVar: - return "GenDeclVar"; - case Stage1AirInstIdBr: - return "GenBr"; - case Stage1AirInstIdCondBr: - return "GenCondBr"; - case Stage1AirInstIdSwitchBr: - return "GenSwitchBr"; - case Stage1AirInstIdPhi: - return "GenPhi"; - case Stage1AirInstIdBinOp: - return "GenBinOp"; - case Stage1AirInstIdLoadPtr: - return "GenLoadPtr"; - case Stage1AirInstIdStorePtr: - return "GenStorePtr"; - case Stage1AirInstIdVectorStoreElem: - return "GenVectorStoreElem"; - case Stage1AirInstIdStructFieldPtr: - return "GenStructFieldPtr"; - case Stage1AirInstIdUnionFieldPtr: - return "GenUnionFieldPtr"; - case Stage1AirInstIdElemPtr: - return "GenElemPtr"; - case Stage1AirInstIdVarPtr: - return "GenVarPtr"; - case Stage1AirInstIdReturnPtr: - return "GenReturnPtr"; - case Stage1AirInstIdCall: - return "GenCall"; - case Stage1AirInstIdConst: - return "GenConst"; - case Stage1AirInstIdReturn: - return "GenReturn"; - case Stage1AirInstIdCast: - return "GenCast"; - case Stage1AirInstIdUnreachable: - return "GenUnreachable"; - case Stage1AirInstIdAsm: - return "GenAsm"; - case Stage1AirInstIdTestNonNull: - return "GenTestNonNull"; - case Stage1AirInstIdOptionalUnwrapPtr: - return "GenOptionalUnwrapPtr"; - case Stage1AirInstIdOptionalWrap: - return "GenOptionalWrap"; - case Stage1AirInstIdUnionTag: - return "GenUnionTag"; - case Stage1AirInstIdClz: - return "GenClz"; - case Stage1AirInstIdCtz: - return "GenCtz"; - case Stage1AirInstIdPopCount: - return "GenPopCount"; - case Stage1AirInstIdBswap: - return "GenBswap"; - case Stage1AirInstIdBitReverse: - return "GenBitReverse"; - case Stage1AirInstIdRef: - return "GenRef"; - case Stage1AirInstIdErrName: - return "GenErrName"; - case Stage1AirInstIdCmpxchg: - return "GenCmpxchg"; - case Stage1AirInstIdFence: - return "GenFence"; - case Stage1AirInstIdReduce: - return "GenReduce"; - case Stage1AirInstIdTruncate: - return "GenTruncate"; - case Stage1AirInstIdBoolNot: - return "GenBoolNot"; - case Stage1AirInstIdMemset: - return "GenMemset"; - case Stage1AirInstIdMemcpy: - return "GenMemcpy"; - case Stage1AirInstIdSlice: - return "GenSlice"; - case Stage1AirInstIdBreakpoint: - return "GenBreakpoint"; - case Stage1AirInstIdReturnAddress: - return "GenReturnAddress"; - case Stage1AirInstIdFrameAddress: - return "GenFrameAddress"; - case Stage1AirInstIdFrameHandle: - return "GenFrameHandle"; - case Stage1AirInstIdFrameSize: - return "GenFrameSize"; - case Stage1AirInstIdOverflowOp: - return "GenOverflowOp"; - case Stage1AirInstIdTestErr: - return "GenTestErr"; - case Stage1AirInstIdMulAdd: - return "GenMulAdd"; - case Stage1AirInstIdFloatOp: - return "GenFloatOp"; - case Stage1AirInstIdUnwrapErrCode: - return "GenUnwrapErrCode"; - case Stage1AirInstIdUnwrapErrPayload: - return "GenUnwrapErrPayload"; - case Stage1AirInstIdErrWrapCode: - return "GenErrWrapCode"; - case Stage1AirInstIdErrWrapPayload: - return "GenErrWrapPayload"; - case Stage1AirInstIdPtrCast: - return "GenPtrCast"; - case Stage1AirInstIdBitCast: - return "GenBitCast"; - case Stage1AirInstIdWidenOrShorten: - return "GenWidenOrShorten"; - case Stage1AirInstIdIntToPtr: - return "GenIntToPtr"; - case Stage1AirInstIdPtrToInt: - return "GenPtrToInt"; - case Stage1AirInstIdIntToEnum: - return "GenIntToEnum"; - case Stage1AirInstIdIntToErr: - return "GenIntToErr"; - case Stage1AirInstIdErrToInt: - return "GenErrToInt"; - case Stage1AirInstIdPanic: - return "GenPanic"; - case Stage1AirInstIdTagName: - return "GenTagName"; - case Stage1AirInstIdFieldParentPtr: - return "GenFieldParentPtr"; - case Stage1AirInstIdAlignCast: - return "GenAlignCast"; - case Stage1AirInstIdErrorReturnTrace: - return "GenErrorReturnTrace"; - case Stage1AirInstIdAtomicRmw: - return "GenAtomicRmw"; - case Stage1AirInstIdAtomicLoad: - return "GenAtomicLoad"; - case Stage1AirInstIdAtomicStore: - return "GenAtomicStore"; - case Stage1AirInstIdSaveErrRetAddr: - return "GenSaveErrRetAddr"; - case Stage1AirInstIdVectorToArray: - return "GenVectorToArray"; - case Stage1AirInstIdArrayToVector: - return "GenArrayToVector"; - case Stage1AirInstIdAssertZero: - return "GenAssertZero"; - case Stage1AirInstIdAssertNonNull: - return "GenAssertNonNull"; - case Stage1AirInstIdAlloca: - return "GenAlloca"; - case Stage1AirInstIdPtrOfArrayToSlice: - return "GenPtrOfArrayToSlice"; - case Stage1AirInstIdSuspendBegin: - return "GenSuspendBegin"; - case Stage1AirInstIdSuspendFinish: - return "GenSuspendFinish"; - case Stage1AirInstIdAwait: - return "GenAwait"; - case Stage1AirInstIdResume: - return "GenResume"; - case Stage1AirInstIdSpillBegin: - return "GenSpillBegin"; - case Stage1AirInstIdSpillEnd: - return "GenSpillEnd"; - case Stage1AirInstIdVectorExtractElem: - return "GenVectorExtractElem"; - case Stage1AirInstIdBinaryNot: - return "GenBinaryNot"; - case Stage1AirInstIdNegation: - return "GenNegation"; - case Stage1AirInstIdWasmMemorySize: - return "GenWasmMemorySize"; - case Stage1AirInstIdWasmMemoryGrow: - return "GenWasmMemoryGrow"; - case Stage1AirInstIdExtern: - return "GenExtern"; - case Stage1AirInstIdPrefetch: - return "GenPrefetch"; - } - zig_unreachable(); -} - -static void ir_print_indent_src(IrPrintSrc *irp) { - for (int i = 0; i < irp->indent; i += 1) { - fprintf(irp->f, " "); - } -} - -static void ir_print_indent_gen(IrPrintGen *irp) { - for (int i = 0; i < irp->indent; i += 1) { - fprintf(irp->f, " "); - } -} - -static void ir_print_prefix_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool trailing) { - ir_print_indent_src(irp); - const char mark = trailing ? ':' : '#'; - const char *type_name; - if (instruction->id == Stage1ZirInstIdConst) { - type_name = buf_ptr(&reinterpret_cast(instruction)->value->type->name); - } else { - type_name = "(unknown)"; - } - const char *ref_count = ir_inst_src_has_side_effects(instruction) ? - "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); - fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, - ir_inst_src_type_str(instruction->id), type_name, ref_count); -} - -static void ir_print_prefix_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool trailing) { - ir_print_indent_gen(irp); - const char mark = trailing ? ':' : '#'; - const char *type_name = instruction->value->type ? buf_ptr(&instruction->value->type->name) : "(unknown)"; - const char *ref_count = ir_inst_gen_has_side_effects(instruction) ? - "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); - fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, - ir_inst_gen_type_str(instruction->id), type_name, ref_count); -} - -static void ir_print_var_src(IrPrintSrc *irp, Stage1ZirInst *inst) { - fprintf(irp->f, "#%" PRIu32 "", inst->debug_id); -} - -static void ir_print_var_gen(IrPrintGen *irp, Stage1AirInst *inst) { - fprintf(irp->f, "#%" PRIu32 "", inst->debug_id); - if (irp->printed.maybe_get(inst) == nullptr) { - irp->printed.put(inst, 0); - irp->pending.append(inst); - } -} - -static void ir_print_other_inst_src(IrPrintSrc *irp, Stage1ZirInst *inst) { - if (inst == nullptr) { - fprintf(irp->f, "(null)"); - return; - } - ir_print_var_src(irp, inst); -} - -static void ir_print_const_value(CodeGen *g, FILE *f, ZigValue *const_val) { - Buf buf = BUF_INIT; - buf_resize(&buf, 0); - render_const_value(g, &buf, const_val); - fprintf(f, "%s", buf_ptr(&buf)); -} - -static void ir_print_other_inst_gen(IrPrintGen *irp, Stage1AirInst *inst) { - if (inst == nullptr) { - fprintf(irp->f, "(null)"); - } else { - ir_print_var_gen(irp, inst); - } -} - -static void ir_print_other_block(IrPrintSrc *irp, Stage1ZirBasicBlock *bb) { - if (bb == nullptr) { - fprintf(irp->f, "(null block)"); - } else { - fprintf(irp->f, "$%s_%" PRIu32 "", bb->name_hint, bb->debug_id); - } -} - -static void ir_print_other_block_gen(IrPrintGen *irp, Stage1AirBasicBlock *bb) { - if (bb == nullptr) { - fprintf(irp->f, "(null block)"); - } else { - fprintf(irp->f, "$%s_%" PRIu32 "", bb->name_hint, bb->debug_id); - } -} - -static void ir_print_return_src(IrPrintSrc *irp, Stage1ZirInstReturn *inst) { - fprintf(irp->f, "return "); - ir_print_other_inst_src(irp, inst->operand); -} - -static void ir_print_return_gen(IrPrintGen *irp, Stage1AirInstReturn *inst) { - fprintf(irp->f, "return "); - ir_print_other_inst_gen(irp, inst->operand); -} - -static void ir_print_const(IrPrintSrc *irp, Stage1ZirInstConst *const_instruction) { - ir_print_const_value(irp->codegen, irp->f, const_instruction->value); -} - -static void ir_print_const(IrPrintGen *irp, Stage1AirInstConst *const_instruction) { - ir_print_const_value(irp->codegen, irp->f, const_instruction->base.value); -} - -static const char *ir_bin_op_id_str(IrBinOp op_id) { - switch (op_id) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpBoolOr: - return "BoolOr"; - case IrBinOpBoolAnd: - return "BoolAnd"; - case IrBinOpCmpEq: - return "=="; - case IrBinOpCmpNotEq: - return "!="; - case IrBinOpCmpLessThan: - return "<"; - case IrBinOpCmpGreaterThan: - return ">"; - case IrBinOpCmpLessOrEq: - return "<="; - case IrBinOpCmpGreaterOrEq: - return ">="; - case IrBinOpBinOr: - return "|"; - case IrBinOpBinXor: - return "^"; - case IrBinOpBinAnd: - return "&"; - case IrBinOpBitShiftLeftLossy: - return "<<"; - case IrBinOpBitShiftLeftExact: - return "@shlExact"; - case IrBinOpBitShiftRightLossy: - return ">>"; - case IrBinOpBitShiftRightExact: - return "@shrExact"; - case IrBinOpAdd: - return "+"; - case IrBinOpAddWrap: - return "+%"; - case IrBinOpSub: - return "-"; - case IrBinOpSubWrap: - return "-%"; - case IrBinOpMult: - return "*"; - case IrBinOpMultWrap: - return "*%"; - case IrBinOpDivUnspecified: - return "/"; - case IrBinOpDivTrunc: - return "@divTrunc"; - case IrBinOpDivFloor: - return "@divFloor"; - case IrBinOpDivExact: - return "@divExact"; - case IrBinOpRemUnspecified: - return "%"; - case IrBinOpRemRem: - return "@rem"; - case IrBinOpRemMod: - return "@mod"; - case IrBinOpArrayCat: - return "++"; - case IrBinOpArrayMult: - return "**"; - case IrBinOpMax: - return "@max"; - case IrBinOpMin: - return "@min"; - case IrBinOpAddSat: - return "@addWithSaturation"; - case IrBinOpSubSat: - return "@subWithSaturation"; - case IrBinOpMultSat: - return "@mulWithSaturation"; - case IrBinOpShlSat: - return "@shlWithSaturation"; - } - zig_unreachable(); -} - -static const char *ir_un_op_id_str(IrUnOp op_id) { - switch (op_id) { - case IrUnOpInvalid: - zig_unreachable(); - case IrUnOpBinNot: - return "~"; - case IrUnOpNegation: - return "-"; - case IrUnOpNegationWrap: - return "-%"; - case IrUnOpDereference: - return "*"; - case IrUnOpOptional: - return "?"; - } - zig_unreachable(); -} - -static void ir_print_un_op(IrPrintSrc *irp, Stage1ZirInstUnOp *inst) { - fprintf(irp->f, "%s ", ir_un_op_id_str(inst->op_id)); - ir_print_other_inst_src(irp, inst->value); -} - -static void ir_print_bin_op(IrPrintSrc *irp, Stage1ZirInstBinOp *bin_op_instruction) { - ir_print_other_inst_src(irp, bin_op_instruction->op1); - fprintf(irp->f, " %s ", ir_bin_op_id_str(bin_op_instruction->op_id)); - ir_print_other_inst_src(irp, bin_op_instruction->op2); - if (!bin_op_instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_bin_op(IrPrintGen *irp, Stage1AirInstBinOp *bin_op_instruction) { - ir_print_other_inst_gen(irp, bin_op_instruction->op1); - fprintf(irp->f, " %s ", ir_bin_op_id_str(bin_op_instruction->op_id)); - ir_print_other_inst_gen(irp, bin_op_instruction->op2); - if (!bin_op_instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_merge_err_sets(IrPrintSrc *irp, Stage1ZirInstMergeErrSets *instruction) { - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, " || "); - ir_print_other_inst_src(irp, instruction->op2); - if (instruction->type_name != nullptr) { - fprintf(irp->f, " // name=%s", buf_ptr(instruction->type_name)); - } -} - -static void ir_print_decl_var_src(IrPrintSrc *irp, Stage1ZirInstDeclVar *decl_var_instruction) { - const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; - const char *name = decl_var_instruction->var->name; - if (decl_var_instruction->var_type) { - fprintf(irp->f, "%s %s: ", var_or_const, name); - ir_print_other_inst_src(irp, decl_var_instruction->var_type); - fprintf(irp->f, " "); - } else { - fprintf(irp->f, "%s %s ", var_or_const, name); - } - if (decl_var_instruction->align_value) { - fprintf(irp->f, "align "); - ir_print_other_inst_src(irp, decl_var_instruction->align_value); - fprintf(irp->f, " "); - } - fprintf(irp->f, "= "); - ir_print_other_inst_src(irp, decl_var_instruction->ptr); - if (decl_var_instruction->var->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, decl_var_instruction->var->is_comptime); - } -} - -static const char *cast_op_str(CastOp op) { - switch (op) { - case CastOpNoCast: return "NoCast"; - case CastOpNoop: return "NoOp"; - case CastOpIntToFloat: return "IntToFloat"; - case CastOpFloatToInt: return "FloatToInt"; - case CastOpBoolToInt: return "BoolToInt"; - case CastOpNumLitToConcrete: return "NumLitToConcrete"; - case CastOpErrSet: return "ErrSet"; - case CastOpBitCast: return "BitCast"; - } - zig_unreachable(); -} - -static void ir_print_cast(IrPrintGen *irp, Stage1AirInstCast *cast_instruction) { - fprintf(irp->f, "%s cast ", cast_op_str(cast_instruction->cast_op)); - ir_print_other_inst_gen(irp, cast_instruction->value); -} - -static void ir_print_result_loc_var(IrPrintSrc *irp, ResultLocVar *result_loc_var) { - fprintf(irp->f, "var("); - ir_print_other_inst_src(irp, result_loc_var->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_instruction(IrPrintSrc *irp, ResultLocInstruction *result_loc_inst) { - fprintf(irp->f, "inst("); - ir_print_other_inst_src(irp, result_loc_inst->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_peer(IrPrintSrc *irp, ResultLocPeer *result_loc_peer) { - fprintf(irp->f, "peer(next="); - ir_print_other_block(irp, result_loc_peer->next_bb); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_bit_cast(IrPrintSrc *irp, ResultLocBitCast *result_loc_bit_cast) { - fprintf(irp->f, "bitcast(ty="); - ir_print_other_inst_src(irp, result_loc_bit_cast->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_cast(IrPrintSrc *irp, ResultLocCast *result_loc_cast) { - fprintf(irp->f, "cast(ty="); - ir_print_other_inst_src(irp, result_loc_cast->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc(IrPrintSrc *irp, ResultLoc *result_loc) { - switch (result_loc->id) { - case ResultLocIdInvalid: - zig_unreachable(); - case ResultLocIdNone: - fprintf(irp->f, "none"); - return; - case ResultLocIdReturn: - fprintf(irp->f, "return"); - return; - case ResultLocIdVar: - return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); - case ResultLocIdInstruction: - return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); - case ResultLocIdPeer: - return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); - case ResultLocIdBitCast: - return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc); - case ResultLocIdCast: - return ir_print_result_loc_cast(irp, (ResultLocCast *)result_loc); - case ResultLocIdPeerParent: - fprintf(irp->f, "peer_parent"); - return; - } - zig_unreachable(); -} - -static void ir_print_call_extra(IrPrintSrc *irp, Stage1ZirInstCallExtra *instruction) { - fprintf(irp->f, "opts="); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - fprintf(irp->f, ", args="); - ir_print_other_inst_src(irp, instruction->args); - fprintf(irp->f, ", result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_async_call_extra(IrPrintSrc *irp, Stage1ZirInstAsyncCallExtra *instruction) { - fprintf(irp->f, "modifier="); - ir_print_call_modifier(irp->f, instruction->modifier); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - if (instruction->ret_ptr != nullptr) { - fprintf(irp->f, ", ret_ptr="); - ir_print_other_inst_src(irp, instruction->ret_ptr); - } - fprintf(irp->f, ", new_stack="); - ir_print_other_inst_src(irp, instruction->new_stack); - fprintf(irp->f, ", args="); - ir_print_other_inst_src(irp, instruction->args); - fprintf(irp->f, ", result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_call_args(IrPrintSrc *irp, Stage1ZirInstCallArgs *instruction) { - fprintf(irp->f, "opts="); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - fprintf(irp->f, ", args=("); - for (size_t i = 0; i < instruction->args_len; i += 1) { - Stage1ZirInst *arg = instruction->args_ptr[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, arg); - } - fprintf(irp->f, "), result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_call_src(IrPrintSrc *irp, Stage1ZirInstCall *call_instruction) { - ir_print_call_modifier(irp->f, call_instruction->modifier); - if (call_instruction->fn_entry) { - fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); - } else { - assert(call_instruction->fn_ref); - ir_print_other_inst_src(irp, call_instruction->fn_ref); - } - fprintf(irp->f, "("); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - Stage1ZirInst *arg = call_instruction->args[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, arg); - } - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, call_instruction->result_loc); -} - -static void ir_print_call_gen(IrPrintGen *irp, Stage1AirInstCall *call_instruction) { - ir_print_call_modifier(irp->f, call_instruction->modifier); - if (call_instruction->fn_entry) { - fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); - } else { - assert(call_instruction->fn_ref); - ir_print_other_inst_gen(irp, call_instruction->fn_ref); - } - fprintf(irp->f, "("); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - Stage1AirInst *arg = call_instruction->args[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, arg); - } - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, call_instruction->result_loc); -} - -static void ir_print_cond_br(IrPrintSrc *irp, Stage1ZirInstCondBr *inst) { - fprintf(irp->f, "if ("); - ir_print_other_inst_src(irp, inst->condition); - fprintf(irp->f, ") "); - ir_print_other_block(irp, inst->then_block); - fprintf(irp->f, " else "); - ir_print_other_block(irp, inst->else_block); - if (inst->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, inst->is_comptime); - } -} - -static void ir_print_cond_br(IrPrintGen *irp, Stage1AirInstCondBr *inst) { - fprintf(irp->f, "if ("); - ir_print_other_inst_gen(irp, inst->condition); - fprintf(irp->f, ") "); - ir_print_other_block_gen(irp, inst->then_block); - fprintf(irp->f, " else "); - ir_print_other_block_gen(irp, inst->else_block); -} - -static void ir_print_br(IrPrintSrc *irp, Stage1ZirInstBr *br_instruction) { - fprintf(irp->f, "goto "); - ir_print_other_block(irp, br_instruction->dest_block); - if (br_instruction->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, br_instruction->is_comptime); - } -} - -static void ir_print_br(IrPrintGen *irp, Stage1AirInstBr *inst) { - fprintf(irp->f, "goto "); - ir_print_other_block_gen(irp, inst->dest_block); -} - -static void ir_print_phi(IrPrintSrc *irp, Stage1ZirInstPhi *phi_instruction) { - assert(phi_instruction->incoming_count != 0); - assert(phi_instruction->incoming_count != SIZE_MAX); - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *incoming_block = phi_instruction->incoming_blocks[i]; - Stage1ZirInst *incoming_value = phi_instruction->incoming_values[i]; - if (i != 0) - fprintf(irp->f, " "); - ir_print_other_block(irp, incoming_block); - fprintf(irp->f, ":"); - ir_print_other_inst_src(irp, incoming_value); - } -} - -static void ir_print_phi(IrPrintGen *irp, Stage1AirInstPhi *phi_instruction) { - assert(phi_instruction->incoming_count != 0); - assert(phi_instruction->incoming_count != SIZE_MAX); - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1AirBasicBlock *incoming_block = phi_instruction->incoming_blocks[i]; - Stage1AirInst *incoming_value = phi_instruction->incoming_values[i]; - if (i != 0) - fprintf(irp->f, " "); - ir_print_other_block_gen(irp, incoming_block); - fprintf(irp->f, ":"); - ir_print_other_inst_gen(irp, incoming_value); - } -} - -static void ir_print_container_init_list(IrPrintSrc *irp, Stage1ZirInstContainerInitList *instruction) { - fprintf(irp->f, "{"); - if (instruction->item_count > 50) { - fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count); - } else { - for (size_t i = 0; i < instruction->item_count; i += 1) { - Stage1ZirInst *result_loc = instruction->elem_result_loc_list[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, result_loc); - } - } - fprintf(irp->f, "}result="); - ir_print_other_inst_src(irp, instruction->result_loc); -} - -static void ir_print_container_init_fields(IrPrintSrc *irp, Stage1ZirInstContainerInitFields *instruction) { - fprintf(irp->f, "{"); - for (size_t i = 0; i < instruction->field_count; i += 1) { - Stage1ZirInstContainerInitFieldsField *field = &instruction->fields[i]; - const char *comma = (i == 0) ? "" : ", "; - fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name)); - ir_print_other_inst_src(irp, field->result_loc); - } - fprintf(irp->f, "}result="); - ir_print_other_inst_src(irp, instruction->result_loc); -} - -static void ir_print_unreachable(IrPrintSrc *irp, Stage1ZirInstUnreachable *instruction) { - fprintf(irp->f, "unreachable"); -} - -static void ir_print_unreachable(IrPrintGen *irp, Stage1AirInstUnreachable *instruction) { - fprintf(irp->f, "unreachable"); -} - -static void ir_print_elem_ptr(IrPrintSrc *irp, Stage1ZirInstElemPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_src(irp, instruction->array_ptr); - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->elem_index); - fprintf(irp->f, "]"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_elem_ptr(IrPrintGen *irp, Stage1AirInstElemPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_gen(irp, instruction->array_ptr); - fprintf(irp->f, "["); - ir_print_other_inst_gen(irp, instruction->elem_index); - fprintf(irp->f, "]"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_var_ptr(IrPrintSrc *irp, Stage1ZirInstVarPtr *instruction) { - fprintf(irp->f, "&%s", instruction->var->name); -} - -static void ir_print_var_ptr(IrPrintGen *irp, Stage1AirInstVarPtr *instruction) { - fprintf(irp->f, "&%s", instruction->var->name); -} - -static void ir_print_return_ptr(IrPrintGen *irp, Stage1AirInstReturnPtr *instruction) { - fprintf(irp->f, "@ReturnPtr"); -} - -static void ir_print_load_ptr(IrPrintSrc *irp, Stage1ZirInstLoadPtr *instruction) { - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ".*"); -} - -static void ir_print_load_ptr_gen(IrPrintGen *irp, Stage1AirInstLoadPtr *instruction) { - fprintf(irp->f, "loadptr("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_store_ptr(IrPrintSrc *irp, Stage1ZirInstStorePtr *instruction) { - fprintf(irp->f, "*"); - ir_print_var_src(irp, instruction->ptr); - fprintf(irp->f, " = "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_store_ptr(IrPrintGen *irp, Stage1AirInstStorePtr *instruction) { - fprintf(irp->f, "*"); - ir_print_var_gen(irp, instruction->ptr); - fprintf(irp->f, " = "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_vector_store_elem(IrPrintGen *irp, Stage1AirInstVectorStoreElem *instruction) { - fprintf(irp->f, "vector_ptr="); - ir_print_var_gen(irp, instruction->vector_ptr); - fprintf(irp->f, ",index="); - ir_print_var_gen(irp, instruction->index); - fprintf(irp->f, ",value="); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_typeof(IrPrintSrc *irp, Stage1ZirInstTypeOf *instruction) { - fprintf(irp->f, "@TypeOf("); - if (instruction->value_count == 1) { - ir_print_other_inst_src(irp, instruction->value.scalar); - } else { - for (size_t i = 0; i < instruction->value_count; i += 1) { - ir_print_other_inst_src(irp, instruction->value.list[i]); - } - } - fprintf(irp->f, ")"); -} - -static void ir_print_binary_not(IrPrintGen *irp, Stage1AirInstBinaryNot *instruction) { - fprintf(irp->f, "~"); - ir_print_other_inst_gen(irp, instruction->operand); -} - -static void ir_print_negation(IrPrintGen *irp, Stage1AirInstNegation *instruction) { - fprintf(irp->f, instruction->wrapping ? "-%%" : "-"); - ir_print_other_inst_gen(irp, instruction->operand); -} - -static void ir_print_field_ptr(IrPrintSrc *irp, Stage1ZirInstFieldPtr *instruction) { - if (instruction->field_name_buffer) { - fprintf(irp->f, "fieldptr "); - ir_print_other_inst_src(irp, instruction->container_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field_name_buffer)); - } else { - assert(instruction->field_name_expr); - fprintf(irp->f, "@field("); - ir_print_other_inst_src(irp, instruction->container_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_name_expr); - fprintf(irp->f, ")"); - } -} - -static void ir_print_struct_field_ptr(IrPrintGen *irp, Stage1AirInstStructFieldPtr *instruction) { - fprintf(irp->f, "@StructFieldPtr(&"); - ir_print_other_inst_gen(irp, instruction->struct_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); - fprintf(irp->f, ")"); -} - -static void ir_print_union_field_ptr(IrPrintGen *irp, Stage1AirInstUnionFieldPtr *instruction) { - fprintf(irp->f, "@UnionFieldPtr(&"); - ir_print_other_inst_gen(irp, instruction->union_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name)); - fprintf(irp->f, ")"); -} - -static void ir_print_set_cold(IrPrintSrc *irp, Stage1ZirInstSetCold *instruction) { - fprintf(irp->f, "@setCold("); - ir_print_other_inst_src(irp, instruction->is_cold); - fprintf(irp->f, ")"); -} - -static void ir_print_set_runtime_safety(IrPrintSrc *irp, Stage1ZirInstSetRuntimeSafety *instruction) { - fprintf(irp->f, "@setRuntimeSafety("); - ir_print_other_inst_src(irp, instruction->safety_on); - fprintf(irp->f, ")"); -} - -static void ir_print_set_float_mode(IrPrintSrc *irp, Stage1ZirInstSetFloatMode *instruction) { - fprintf(irp->f, "@setFloatMode("); - ir_print_other_inst_src(irp, instruction->scope_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->mode_value); - fprintf(irp->f, ")"); -} - -static void ir_print_array_type(IrPrintSrc *irp, Stage1ZirInstArrayType *instruction) { - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->size); - if (instruction->sentinel != nullptr) { - fprintf(irp->f, ":"); - ir_print_other_inst_src(irp, instruction->sentinel); - } - fprintf(irp->f, "]"); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_slice_type(IrPrintSrc *irp, Stage1ZirInstSliceType *instruction) { - const char *const_kw = instruction->is_const ? "const " : ""; - fprintf(irp->f, "[]%s", const_kw); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_any_frame_type(IrPrintSrc *irp, Stage1ZirInstAnyFrameType *instruction) { - if (instruction->payload_type == nullptr) { - fprintf(irp->f, "anyframe"); - } else { - fprintf(irp->f, "anyframe->"); - ir_print_other_inst_src(irp, instruction->payload_type); - } -} - -static void ir_print_asm_src(IrPrintSrc *irp, Stage1ZirInstAsm *instruction) { - assert(instruction->base.source_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr; - const char *volatile_kw = instruction->has_side_effects ? " volatile" : ""; - fprintf(irp->f, "asm%s (", volatile_kw); - ir_print_other_inst_src(irp, instruction->asm_template); - - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_output->asm_symbolic_name), - buf_ptr(asm_output->constraint)); - if (asm_output->return_type) { - fprintf(irp->f, "-> "); - ir_print_other_inst_src(irp, instruction->output_types[i]); - } else { - fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name)); - } - fprintf(irp->f, ")"); - } - - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_input->asm_symbolic_name), - buf_ptr(asm_input->constraint)); - ir_print_other_inst_src(irp, instruction->input_list[i]); - fprintf(irp->f, ")"); - } - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) { - Buf *reg_name = asm_expr->clobber_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "\"%s\"", buf_ptr(reg_name)); - } - fprintf(irp->f, ")"); -} - -static void ir_print_asm_gen(IrPrintGen *irp, Stage1AirInstAsm *instruction) { - assert(instruction->base.source_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr; - const char *volatile_kw = instruction->has_side_effects ? " volatile" : ""; - fprintf(irp->f, "asm%s (\"%s\") : ", volatile_kw, buf_ptr(instruction->asm_template)); - - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_output->asm_symbolic_name), - buf_ptr(asm_output->constraint)); - if (asm_output->return_type) { - fprintf(irp->f, "-> "); - ir_print_other_inst_gen(irp, instruction->output_types[i]); - } else { - fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name)); - } - fprintf(irp->f, ")"); - } - - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_input->asm_symbolic_name), - buf_ptr(asm_input->constraint)); - ir_print_other_inst_gen(irp, instruction->input_list[i]); - fprintf(irp->f, ")"); - } - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) { - Buf *reg_name = asm_expr->clobber_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "\"%s\"", buf_ptr(reg_name)); - } - fprintf(irp->f, ")"); -} - -static void ir_print_size_of(IrPrintSrc *irp, Stage1ZirInstSizeOf *instruction) { - if (instruction->bit_size) - fprintf(irp->f, "@bitSizeOf("); - else - fprintf(irp->f, "@sizeOf("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_test_non_null(IrPrintSrc *irp, Stage1ZirInstTestNonNull *instruction) { - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, " != null"); -} - -static void ir_print_test_non_null(IrPrintGen *irp, Stage1AirInstTestNonNull *instruction) { - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, " != null"); -} - -static void ir_print_optional_unwrap_ptr(IrPrintSrc *irp, Stage1ZirInstOptionalUnwrapPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_src(irp, instruction->base_ptr); - fprintf(irp->f, ".*.?"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_optional_unwrap_ptr(IrPrintGen *irp, Stage1AirInstOptionalUnwrapPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_gen(irp, instruction->base_ptr); - fprintf(irp->f, ".*.?"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_clz(IrPrintSrc *irp, Stage1ZirInstClz *instruction) { - fprintf(irp->f, "@clz("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_clz(IrPrintGen *irp, Stage1AirInstClz *instruction) { - fprintf(irp->f, "@clz("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_ctz(IrPrintSrc *irp, Stage1ZirInstCtz *instruction) { - fprintf(irp->f, "@ctz("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_ctz(IrPrintGen *irp, Stage1AirInstCtz *instruction) { - fprintf(irp->f, "@ctz("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_pop_count(IrPrintSrc *irp, Stage1ZirInstPopCount *instruction) { - fprintf(irp->f, "@popCount("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_pop_count(IrPrintGen *irp, Stage1AirInstPopCount *instruction) { - fprintf(irp->f, "@popCount("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bswap(IrPrintSrc *irp, Stage1ZirInstBswap *instruction) { - fprintf(irp->f, "@byteSwap("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bswap(IrPrintGen *irp, Stage1AirInstBswap *instruction) { - fprintf(irp->f, "@byteSwap("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_reverse(IrPrintSrc *irp, Stage1ZirInstBitReverse *instruction) { - fprintf(irp->f, "@bitReverse("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_reverse(IrPrintGen *irp, Stage1AirInstBitReverse *instruction) { - fprintf(irp->f, "@bitReverse("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_switch_br(IrPrintSrc *irp, Stage1ZirInstSwitchBr *instruction) { - fprintf(irp->f, "switch ("); - ir_print_other_inst_src(irp, instruction->target_value); - fprintf(irp->f, ") "); - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1ZirInstSwitchBrCase *this_case = &instruction->cases[i]; - ir_print_other_inst_src(irp, this_case->value); - fprintf(irp->f, " => "); - ir_print_other_block(irp, this_case->block); - fprintf(irp->f, ", "); - } - fprintf(irp->f, "else => "); - ir_print_other_block(irp, instruction->else_block); - if (instruction->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, instruction->is_comptime); - } -} - -static void ir_print_switch_br(IrPrintGen *irp, Stage1AirInstSwitchBr *instruction) { - fprintf(irp->f, "switch ("); - ir_print_other_inst_gen(irp, instruction->target_value); - fprintf(irp->f, ") "); - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1AirInstSwitchBrCase *this_case = &instruction->cases[i]; - ir_print_other_inst_gen(irp, this_case->value); - fprintf(irp->f, " => "); - ir_print_other_block_gen(irp, this_case->block); - fprintf(irp->f, ", "); - } - fprintf(irp->f, "else => "); - ir_print_other_block_gen(irp, instruction->else_block); -} - -static void ir_print_switch_var(IrPrintSrc *irp, Stage1ZirInstSwitchVar *instruction) { - fprintf(irp->f, "switchvar "); - ir_print_other_inst_src(irp, instruction->target_value_ptr); - for (size_t i = 0; i < instruction->prongs_len; i += 1) { - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->prongs_ptr[i]); - } -} - -static void ir_print_switch_else_var(IrPrintSrc *irp, Stage1ZirInstSwitchElseVar *instruction) { - fprintf(irp->f, "switchelsevar "); - ir_print_other_inst_src(irp, &instruction->switch_br->base); -} - -static void ir_print_switch_target(IrPrintSrc *irp, Stage1ZirInstSwitchTarget *instruction) { - fprintf(irp->f, "switchtarget "); - ir_print_other_inst_src(irp, instruction->target_value_ptr); -} - -static void ir_print_union_tag(IrPrintGen *irp, Stage1AirInstUnionTag *instruction) { - fprintf(irp->f, "uniontag "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_import(IrPrintSrc *irp, Stage1ZirInstImport *instruction) { - fprintf(irp->f, "@import("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_ref(IrPrintSrc *irp, Stage1ZirInstRef *instruction) { - fprintf(irp->f, "ref "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_ref_gen(IrPrintGen *irp, Stage1AirInstRef *instruction) { - fprintf(irp->f, "@ref("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_compile_err(IrPrintSrc *irp, Stage1ZirInstCompileErr *instruction) { - fprintf(irp->f, "@compileError("); - ir_print_other_inst_src(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_compile_log(IrPrintSrc *irp, Stage1ZirInstCompileLog *instruction) { - fprintf(irp->f, "@compileLog("); - for (size_t i = 0; i < instruction->msg_count; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - Stage1ZirInst *msg = instruction->msg_list[i]; - ir_print_other_inst_src(irp, msg); - } - fprintf(irp->f, ")"); -} - -static void ir_print_err_name(IrPrintSrc *irp, Stage1ZirInstErrName *instruction) { - fprintf(irp->f, "@errorName("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_err_name(IrPrintGen *irp, Stage1AirInstErrName *instruction) { - fprintf(irp->f, "@errorName("); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_c_import(IrPrintSrc *irp, Stage1ZirInstCImport *instruction) { - fprintf(irp->f, "@cImport(...)"); -} - -static void ir_print_c_include(IrPrintSrc *irp, Stage1ZirInstCInclude *instruction) { - fprintf(irp->f, "@cInclude("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_c_define(IrPrintSrc *irp, Stage1ZirInstCDefine *instruction) { - fprintf(irp->f, "@cDefine("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_c_undef(IrPrintSrc *irp, Stage1ZirInstCUndef *instruction) { - fprintf(irp->f, "@cUndef("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_embed_file(IrPrintSrc *irp, Stage1ZirInstEmbedFile *instruction) { - fprintf(irp->f, "@embedFile("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_cmpxchg_src(IrPrintSrc *irp, Stage1ZirInstCmpxchg *instruction) { - fprintf(irp->f, "@cmpxchg("); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->cmp_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->new_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->success_order_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->failure_order_value); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_cmpxchg_gen(IrPrintGen *irp, Stage1AirInstCmpxchg *instruction) { - fprintf(irp->f, "@cmpxchg("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->cmp_value); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->new_value); - fprintf(irp->f, ", TODO print atomic orders)result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_fence(IrPrintSrc *irp, Stage1ZirInstFence *instruction) { - fprintf(irp->f, "@fence("); - ir_print_other_inst_src(irp, instruction->order); - fprintf(irp->f, ")"); -} - -static void ir_print_reduce(IrPrintSrc *irp, Stage1ZirInstReduce *instruction) { - fprintf(irp->f, "@reduce("); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static const char *atomic_order_str(AtomicOrder order) { - switch (order) { - case AtomicOrderUnordered: return "Unordered"; - case AtomicOrderMonotonic: return "Monotonic"; - case AtomicOrderAcquire: return "Acquire"; - case AtomicOrderRelease: return "Release"; - case AtomicOrderAcqRel: return "AcqRel"; - case AtomicOrderSeqCst: return "SeqCst"; - } - zig_unreachable(); -} - -static void ir_print_fence(IrPrintGen *irp, Stage1AirInstFence *instruction) { - fprintf(irp->f, "fence %s", atomic_order_str(instruction->order)); -} - -static const char *reduce_op_str(ReduceOp op) { - switch (op) { - case ReduceOp_and: return "And"; - case ReduceOp_or: return "Or"; - case ReduceOp_xor: return "Xor"; - case ReduceOp_min: return "Min"; - case ReduceOp_max: return "Max"; - case ReduceOp_add: return "Add"; - case ReduceOp_mul: return "Mul"; - } - zig_unreachable(); -} - -static void ir_print_reduce(IrPrintGen *irp, Stage1AirInstReduce *instruction) { - fprintf(irp->f, "@reduce(.%s, ", reduce_op_str(instruction->op)); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_truncate(IrPrintSrc *irp, Stage1ZirInstTruncate *instruction) { - fprintf(irp->f, "@truncate("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_truncate(IrPrintGen *irp, Stage1AirInstTruncate *instruction) { - fprintf(irp->f, "@truncate("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_cast(IrPrintSrc *irp, Stage1ZirInstIntCast *instruction) { - fprintf(irp->f, "@intCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_float_cast(IrPrintSrc *irp, Stage1ZirInstFloatCast *instruction) { - fprintf(irp->f, "@floatCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_err_set_cast(IrPrintSrc *irp, Stage1ZirInstErrSetCast *instruction) { - fprintf(irp->f, "@errSetCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_float(IrPrintSrc *irp, Stage1ZirInstIntToFloat *instruction) { - fprintf(irp->f, "@intToFloat("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_float_to_int(IrPrintSrc *irp, Stage1ZirInstFloatToInt *instruction) { - fprintf(irp->f, "@floatToInt("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_bool_to_int(IrPrintSrc *irp, Stage1ZirInstBoolToInt *instruction) { - fprintf(irp->f, "@boolToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_type(IrPrintSrc *irp, Stage1ZirInstVectorType *instruction) { - fprintf(irp->f, "@Vector("); - ir_print_other_inst_src(irp, instruction->len); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->elem_type); - fprintf(irp->f, ")"); -} - -static void ir_print_shuffle_vector(IrPrintSrc *irp, Stage1ZirInstShuffleVector *instruction) { - fprintf(irp->f, "@shuffle("); - ir_print_other_inst_src(irp, instruction->scalar_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->b); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->mask); - fprintf(irp->f, ")"); -} - -static void ir_print_shuffle_vector(IrPrintGen *irp, Stage1AirInstShuffleVector *instruction) { - fprintf(irp->f, "@shuffle("); - ir_print_other_inst_gen(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->b); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->mask); - fprintf(irp->f, ")"); -} - -static void ir_print_select(IrPrintSrc *irp, Stage1ZirInstSelect *instruction) { - fprintf(irp->f, "@select("); - ir_print_other_inst_src(irp, instruction->scalar_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->pred); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->b); - fprintf(irp->f, ")"); -} - -static void ir_print_select(IrPrintGen *irp, Stage1AirInstSelect *instruction) { - fprintf(irp->f, "@select("); - ir_print_other_inst_gen(irp, instruction->pred); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->b); - fprintf(irp->f, ")"); -} - -static void ir_print_splat_src(IrPrintSrc *irp, Stage1ZirInstSplat *instruction) { - fprintf(irp->f, "@splat("); - ir_print_other_inst_src(irp, instruction->len); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->scalar); - fprintf(irp->f, ")"); -} - -static void ir_print_splat_gen(IrPrintGen *irp, Stage1AirInstSplat *instruction) { - fprintf(irp->f, "@splat("); - ir_print_other_inst_gen(irp, instruction->scalar); - fprintf(irp->f, ")"); -} - -static void ir_print_bool_not(IrPrintSrc *irp, Stage1ZirInstBoolNot *instruction) { - fprintf(irp->f, "! "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_bool_not(IrPrintGen *irp, Stage1AirInstBoolNot *instruction) { - fprintf(irp->f, "! "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_wasm_memory_size(IrPrintSrc *irp, Stage1ZirInstWasmMemorySize *instruction) { - fprintf(irp->f, "@wasmMemorySize("); - ir_print_other_inst_src(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_size(IrPrintGen *irp, Stage1AirInstWasmMemorySize *instruction) { - fprintf(irp->f, "@wasmMemorySize("); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_grow(IrPrintSrc *irp, Stage1ZirInstWasmMemoryGrow *instruction) { - fprintf(irp->f, "@wasmMemoryGrow("); - ir_print_other_inst_src(irp, instruction->index); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->delta); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_grow(IrPrintGen *irp, Stage1AirInstWasmMemoryGrow *instruction) { - fprintf(irp->f, "@wasmMemoryGrow("); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->delta); - fprintf(irp->f, ")"); -} - -static void ir_print_builtin_src(IrPrintSrc *irp, Stage1ZirInstSrc *instruction) { - fprintf(irp->f, "@src()"); -} - -static void ir_print_memset(IrPrintSrc *irp, Stage1ZirInstMemset *instruction) { - fprintf(irp->f, "@memset("); - ir_print_other_inst_src(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->byte); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memset(IrPrintGen *irp, Stage1AirInstMemset *instruction) { - fprintf(irp->f, "@memset("); - ir_print_other_inst_gen(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->byte); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memcpy(IrPrintSrc *irp, Stage1ZirInstMemcpy *instruction) { - fprintf(irp->f, "@memcpy("); - ir_print_other_inst_src(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->src_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memcpy(IrPrintGen *irp, Stage1AirInstMemcpy *instruction) { - fprintf(irp->f, "@memcpy("); - ir_print_other_inst_gen(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->src_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_slice_src(IrPrintSrc *irp, Stage1ZirInstSlice *instruction) { - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->start); - fprintf(irp->f, ".."); - if (instruction->end) - ir_print_other_inst_src(irp, instruction->end); - fprintf(irp->f, "]result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_slice_gen(IrPrintGen *irp, Stage1AirInstSlice *instruction) { - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, "["); - ir_print_other_inst_gen(irp, instruction->start); - fprintf(irp->f, ".."); - if (instruction->end) - ir_print_other_inst_gen(irp, instruction->end); - fprintf(irp->f, "]result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_breakpoint(IrPrintSrc *irp, Stage1ZirInstBreakpoint *instruction) { - fprintf(irp->f, "@breakpoint()"); -} - -static void ir_print_breakpoint(IrPrintGen *irp, Stage1AirInstBreakpoint *instruction) { - fprintf(irp->f, "@breakpoint()"); -} - -static void ir_print_frame_address(IrPrintSrc *irp, Stage1ZirInstFrameAddress *instruction) { - fprintf(irp->f, "@frameAddress()"); -} - -static void ir_print_frame_address(IrPrintGen *irp, Stage1AirInstFrameAddress *instruction) { - fprintf(irp->f, "@frameAddress()"); -} - -static void ir_print_handle(IrPrintSrc *irp, Stage1ZirInstFrameHandle *instruction) { - fprintf(irp->f, "@frame()"); -} - -static void ir_print_handle(IrPrintGen *irp, Stage1AirInstFrameHandle *instruction) { - fprintf(irp->f, "@frame()"); -} - -static void ir_print_frame_type(IrPrintSrc *irp, Stage1ZirInstFrameType *instruction) { - fprintf(irp->f, "@Frame("); - ir_print_other_inst_src(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_frame_size_src(IrPrintSrc *irp, Stage1ZirInstFrameSize *instruction) { - fprintf(irp->f, "@frameSize("); - ir_print_other_inst_src(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_frame_size_gen(IrPrintGen *irp, Stage1AirInstFrameSize *instruction) { - fprintf(irp->f, "@frameSize("); - ir_print_other_inst_gen(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_return_address(IrPrintSrc *irp, Stage1ZirInstReturnAddress *instruction) { - fprintf(irp->f, "@returnAddress()"); -} - -static void ir_print_return_address(IrPrintGen *irp, Stage1AirInstReturnAddress *instruction) { - fprintf(irp->f, "@returnAddress()"); -} - -static void ir_print_align_of(IrPrintSrc *irp, Stage1ZirInstAlignOf *instruction) { - fprintf(irp->f, "@alignOf("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_overflow_op(IrPrintSrc *irp, Stage1ZirInstOverflowOp *instruction) { - switch (instruction->op) { - case IrOverflowOpAdd: - fprintf(irp->f, "@addWithOverflow("); - break; - case IrOverflowOpSub: - fprintf(irp->f, "@subWithOverflow("); - break; - case IrOverflowOpMul: - fprintf(irp->f, "@mulWithOverflow("); - break; - case IrOverflowOpShl: - fprintf(irp->f, "@shlWithOverflow("); - break; - } - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->op2); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->result_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_overflow_op(IrPrintGen *irp, Stage1AirInstOverflowOp *instruction) { - switch (instruction->op) { - case IrOverflowOpAdd: - fprintf(irp->f, "@addWithOverflow("); - break; - case IrOverflowOpSub: - fprintf(irp->f, "@subWithOverflow("); - break; - case IrOverflowOpMul: - fprintf(irp->f, "@mulWithOverflow("); - break; - case IrOverflowOpShl: - fprintf(irp->f, "@shlWithOverflow("); - break; - } - ir_print_other_inst_gen(irp, instruction->op1); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->op2); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->result_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_test_err_src(IrPrintSrc *irp, Stage1ZirInstTestErr *instruction) { - fprintf(irp->f, "@testError("); - ir_print_other_inst_src(irp, instruction->base_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_test_err_gen(IrPrintGen *irp, Stage1AirInstTestErr *instruction) { - fprintf(irp->f, "@testError("); - ir_print_other_inst_gen(irp, instruction->err_union); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_code(IrPrintSrc *irp, Stage1ZirInstUnwrapErrCode *instruction) { - fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_inst_src(irp, instruction->err_union_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_code(IrPrintGen *irp, Stage1AirInstUnwrapErrCode *instruction) { - fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_inst_gen(irp, instruction->err_union_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_payload(IrPrintSrc *irp, Stage1ZirInstUnwrapErrPayload *instruction) { - fprintf(irp->f, "ErrorUnionFieldPayload("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); -} - -static void ir_print_unwrap_err_payload(IrPrintGen *irp, Stage1AirInstUnwrapErrPayload *instruction) { - fprintf(irp->f, "ErrorUnionFieldPayload("); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); -} - -static void ir_print_optional_wrap(IrPrintGen *irp, Stage1AirInstOptionalWrap *instruction) { - fprintf(irp->f, "@optionalWrap("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_err_wrap_code(IrPrintGen *irp, Stage1AirInstErrWrapCode *instruction) { - fprintf(irp->f, "@errWrapCode("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_err_wrap_payload(IrPrintGen *irp, Stage1AirInstErrWrapPayload *instruction) { - fprintf(irp->f, "@errWrapPayload("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_fn_proto(IrPrintSrc *irp, Stage1ZirInstFnProto *instruction) { - fprintf(irp->f, "fn("); - for (size_t i = 0; i < instruction->base.source_node->data.fn_proto.params.length; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - if (instruction->is_var_args && i == instruction->base.source_node->data.fn_proto.params.length - 1) { - fprintf(irp->f, "..."); - } else { - ir_print_other_inst_src(irp, instruction->param_types[i]); - } - } - fprintf(irp->f, ")"); - if (instruction->align_value != nullptr) { - fprintf(irp->f, " align "); - ir_print_other_inst_src(irp, instruction->align_value); - fprintf(irp->f, " "); - } - fprintf(irp->f, "->"); - ir_print_other_inst_src(irp, instruction->return_type); -} - -static void ir_print_test_comptime(IrPrintSrc *irp, Stage1ZirInstTestComptime *instruction) { - fprintf(irp->f, "@testComptime("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_cast_src(IrPrintSrc *irp, Stage1ZirInstPtrCast *instruction) { - fprintf(irp->f, "@ptrCast("); - if (instruction->dest_type) { - ir_print_other_inst_src(irp, instruction->dest_type); - } - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_cast_gen(IrPrintGen *irp, Stage1AirInstPtrCast *instruction) { - fprintf(irp->f, "@ptrCast("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_implicit_cast(IrPrintSrc *irp, Stage1ZirInstImplicitCast *instruction) { - fprintf(irp->f, "@implicitCast("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, &instruction->result_loc_cast->base); -} - -static void ir_print_bit_cast_src(IrPrintSrc *irp, Stage1ZirInstBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, &instruction->result_loc_bit_cast->base); -} - -static void ir_print_bit_cast_gen(IrPrintGen *irp, Stage1AirInstBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_widen_or_shorten(IrPrintGen *irp, Stage1AirInstWidenOrShorten *instruction) { - fprintf(irp->f, "WidenOrShorten("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_to_int(IrPrintSrc *irp, Stage1ZirInstPtrToInt *instruction) { - fprintf(irp->f, "@ptrToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_to_int(IrPrintGen *irp, Stage1AirInstPtrToInt *instruction) { - fprintf(irp->f, "@ptrToInt("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_ptr(IrPrintSrc *irp, Stage1ZirInstIntToPtr *instruction) { - fprintf(irp->f, "@intToPtr("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_ptr(IrPrintGen *irp, Stage1AirInstIntToPtr *instruction) { - fprintf(irp->f, "@intToPtr("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_enum(IrPrintSrc *irp, Stage1ZirInstIntToEnum *instruction) { - fprintf(irp->f, "@intToEnum("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_enum(IrPrintGen *irp, Stage1AirInstIntToEnum *instruction) { - fprintf(irp->f, "@intToEnum("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_enum_to_int(IrPrintSrc *irp, Stage1ZirInstEnumToInt *instruction) { - fprintf(irp->f, "@enumToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_check_runtime_scope(IrPrintSrc *irp, Stage1ZirInstCheckRuntimeScope *instruction) { - fprintf(irp->f, "@checkRuntimeScope("); - ir_print_other_inst_src(irp, instruction->scope_is_comptime); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->is_comptime); - fprintf(irp->f, ")"); -} - -static void ir_print_array_to_vector(IrPrintGen *irp, Stage1AirInstArrayToVector *instruction) { - fprintf(irp->f, "ArrayToVector("); - ir_print_other_inst_gen(irp, instruction->array); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_to_array(IrPrintGen *irp, Stage1AirInstVectorToArray *instruction) { - fprintf(irp->f, "VectorToArray("); - ir_print_other_inst_gen(irp, instruction->vector); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_ptr_of_array_to_slice(IrPrintGen *irp, Stage1AirInstPtrOfArrayToSlice *instruction) { - fprintf(irp->f, "PtrOfArrayToSlice("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_assert_zero(IrPrintGen *irp, Stage1AirInstAssertZero *instruction) { - fprintf(irp->f, "AssertZero("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_assert_non_null(IrPrintGen *irp, Stage1AirInstAssertNonNull *instruction) { - fprintf(irp->f, "AssertNonNull("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_alloca_src(IrPrintSrc *irp, Stage1ZirInstAlloca *instruction) { - fprintf(irp->f, "Alloca(align="); - ir_print_other_inst_src(irp, instruction->align); - fprintf(irp->f, ",name=%s)", instruction->name_hint); -} - -static void ir_print_alloca_gen(IrPrintGen *irp, Stage1AirInstAlloca *instruction) { - fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint); -} - -static void ir_print_end_expr(IrPrintSrc *irp, Stage1ZirInstEndExpr *instruction) { - fprintf(irp->f, "EndExpr(result="); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ",value="); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_err(IrPrintSrc *irp, Stage1ZirInstIntToErr *instruction) { - fprintf(irp->f, "inttoerr "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_int_to_err(IrPrintGen *irp, Stage1AirInstIntToErr *instruction) { - fprintf(irp->f, "inttoerr "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_err_to_int(IrPrintSrc *irp, Stage1ZirInstErrToInt *instruction) { - fprintf(irp->f, "errtoint "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_err_to_int(IrPrintGen *irp, Stage1AirInstErrToInt *instruction) { - fprintf(irp->f, "errtoint "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_check_switch_prongs(IrPrintSrc *irp, Stage1ZirInstCheckSwitchProngs *instruction, - bool have_underscore_prong) -{ - fprintf(irp->f, "@checkSwitchProngs("); - ir_print_other_inst_src(irp, instruction->target_value); - fprintf(irp->f, ","); - for (size_t i = 0; i < instruction->range_count; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ranges[i].start); - fprintf(irp->f, "..."); - ir_print_other_inst_src(irp, instruction->ranges[i].end); - } - const char *have_else_str = instruction->else_prong != nullptr ? "yes" : "no"; - fprintf(irp->f, ")else:%s", have_else_str); - const char *have_under_str = have_underscore_prong ? "yes" : "no"; - fprintf(irp->f, " _:%s", have_under_str); -} - -static void ir_print_check_statement_is_void(IrPrintSrc *irp, Stage1ZirInstCheckStatementIsVoid *instruction) { - fprintf(irp->f, "@checkStatementIsVoid("); - ir_print_other_inst_src(irp, instruction->statement_value); - fprintf(irp->f, ")"); -} - -static void ir_print_type_name(IrPrintSrc *irp, Stage1ZirInstTypeName *instruction) { - fprintf(irp->f, "typename "); - ir_print_other_inst_src(irp, instruction->type_value); -} - -static void ir_print_tag_name(IrPrintSrc *irp, Stage1ZirInstTagName *instruction) { - fprintf(irp->f, "tagname "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_tag_name(IrPrintGen *irp, Stage1AirInstTagName *instruction) { - fprintf(irp->f, "tagname "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_ptr_type(IrPrintSrc *irp, Stage1ZirInstPtrType *instruction) { - fprintf(irp->f, "&"); - if (instruction->align_value != nullptr) { - fprintf(irp->f, "align("); - ir_print_other_inst_src(irp, instruction->align_value); - fprintf(irp->f, ")"); - } - const char *const_str = instruction->is_const ? "const " : ""; - const char *volatile_str = instruction->is_volatile ? "volatile " : ""; - fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->host_int_bytes, - const_str, volatile_str); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_ptr_type_simple(IrPrintSrc *irp, Stage1ZirInstPtrTypeSimple *instruction, - bool is_const) -{ - fprintf(irp->f, "&"); - const char *const_str = is_const ? "const " : ""; - fprintf(irp->f, "*%s", const_str); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_decl_ref(IrPrintSrc *irp, Stage1ZirInstDeclRef *instruction) { - const char *ptr_str = (instruction->lval != LValNone) ? "ptr " : ""; - fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name)); -} - -static void ir_print_panic(IrPrintSrc *irp, Stage1ZirInstPanic *instruction) { - fprintf(irp->f, "@panic("); - ir_print_other_inst_src(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_panic(IrPrintGen *irp, Stage1AirInstPanic *instruction) { - fprintf(irp->f, "@panic("); - ir_print_other_inst_gen(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_field_parent_ptr(IrPrintSrc *irp, Stage1ZirInstFieldParentPtr *instruction) { - fprintf(irp->f, "@fieldParentPtr("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_field_parent_ptr(IrPrintGen *irp, Stage1AirInstFieldParentPtr *instruction) { - fprintf(irp->f, "@fieldParentPtr(%s,", buf_ptr(instruction->field->name)); - ir_print_other_inst_gen(irp, instruction->field_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_offset_of(IrPrintSrc *irp, Stage1ZirInstOffsetOf *instruction) { - fprintf(irp->f, "@offset_of("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_offset_of(IrPrintSrc *irp, Stage1ZirInstBitOffsetOf *instruction) { - fprintf(irp->f, "@bit_offset_of("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_type_info(IrPrintSrc *irp, Stage1ZirInstTypeInfo *instruction) { - fprintf(irp->f, "@typeInfo("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_type(IrPrintSrc *irp, Stage1ZirInstType *instruction) { - fprintf(irp->f, "@Type("); - ir_print_other_inst_src(irp, instruction->type_info); - fprintf(irp->f, ")"); -} - -static void ir_print_has_field(IrPrintSrc *irp, Stage1ZirInstHasField *instruction) { - fprintf(irp->f, "@hasField("); - ir_print_other_inst_src(irp, instruction->container_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_set_eval_branch_quota(IrPrintSrc *irp, Stage1ZirInstSetEvalBranchQuota *instruction) { - fprintf(irp->f, "@setEvalBranchQuota("); - ir_print_other_inst_src(irp, instruction->new_quota); - fprintf(irp->f, ")"); -} - -static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruction) { - fprintf(irp->f, "@alignCast("); - ir_print_other_inst_src(irp, instruction->align_bytes); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_addrspace_cast(IrPrintSrc *irp, Stage1ZirInstAddrSpaceCast *instruction) { - fprintf(irp->f, "@addrSpaceCast("); - ir_print_other_inst_src(irp, instruction->addrspace); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) { - fprintf(irp->f, "@alignCast("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_resolve_result(IrPrintSrc *irp, Stage1ZirInstResolveResult *instruction) { - fprintf(irp->f, "ResolveResult("); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_reset_result(IrPrintSrc *irp, Stage1ZirInstResetResult *instruction) { - fprintf(irp->f, "ResetResult("); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_set_align_stack(IrPrintSrc *irp, Stage1ZirInstSetAlignStack *instruction) { - fprintf(irp->f, "@setAlignStack("); - ir_print_other_inst_src(irp, instruction->align_bytes); - fprintf(irp->f, ")"); -} - -static void ir_print_arg_type(IrPrintSrc *irp, Stage1ZirInstArgType *instruction, bool allow_var) { - fprintf(irp->f, "@ArgType("); - ir_print_other_inst_src(irp, instruction->fn_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->arg_index); - fprintf(irp->f, ","); - if (allow_var) { - fprintf(irp->f, "allow_var=true"); - } else { - fprintf(irp->f, "allow_var=false"); - } - fprintf(irp->f, ")"); -} - -static void ir_print_export(IrPrintSrc *irp, Stage1ZirInstExport *instruction) { - fprintf(irp->f, "@export("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_extern(IrPrintGen *irp, Stage1AirInstExtern *instruction) { - fprintf(irp->f, "@extern(...)"); -} - -static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) { - fprintf(irp->f, "@extern("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_prefetch(IrPrintSrc *irp, Stage1ZirInstPrefetch *instruction) { - fprintf(irp->f, "@prefetch("); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_prefetch(IrPrintGen *irp, Stage1AirInstPrefetch *instruction) { - fprintf(irp->f, "@prefetch(...)"); -} - -static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) { - fprintf(irp->f, "@errorReturnTrace("); - switch (instruction->optional) { - case IrInstErrorReturnTraceNull: - fprintf(irp->f, "Null"); - break; - case IrInstErrorReturnTraceNonNull: - fprintf(irp->f, "NonNull"); - break; - } - fprintf(irp->f, ")"); -} - -static void ir_print_error_return_trace(IrPrintGen *irp, Stage1AirInstErrorReturnTrace *instruction) { - fprintf(irp->f, "@errorReturnTrace("); - switch (instruction->optional) { - case IrInstErrorReturnTraceNull: - fprintf(irp->f, "Null"); - break; - case IrInstErrorReturnTraceNonNull: - fprintf(irp->f, "NonNull"); - break; - } - fprintf(irp->f, ")"); -} - -static void ir_print_error_union(IrPrintSrc *irp, Stage1ZirInstErrorUnion *instruction) { - ir_print_other_inst_src(irp, instruction->err_set); - fprintf(irp->f, "!"); - ir_print_other_inst_src(irp, instruction->payload); -} - -static void ir_print_atomic_rmw(IrPrintSrc *irp, Stage1ZirInstAtomicRmw *instruction) { - fprintf(irp->f, "@atomicRmw("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_rmw(IrPrintGen *irp, Stage1AirInstAtomicRmw *instruction) { - fprintf(irp->f, "@atomicRmw("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ",[TODO print op],"); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - -static void ir_print_atomic_load(IrPrintSrc *irp, Stage1ZirInstAtomicLoad *instruction) { - fprintf(irp->f, "@atomicLoad("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_load(IrPrintGen *irp, Stage1AirInstAtomicLoad *instruction) { - fprintf(irp->f, "@atomicLoad("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - -static void ir_print_atomic_store(IrPrintSrc *irp, Stage1ZirInstAtomicStore *instruction) { - fprintf(irp->f, "@atomicStore("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_store(IrPrintGen *irp, Stage1AirInstAtomicStore *instruction) { - fprintf(irp->f, "@atomicStore("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - - -static void ir_print_save_err_ret_addr(IrPrintSrc *irp, Stage1ZirInstSaveErrRetAddr *instruction) { - fprintf(irp->f, "@saveErrRetAddr()"); -} - -static void ir_print_save_err_ret_addr(IrPrintGen *irp, Stage1AirInstSaveErrRetAddr *instruction) { - fprintf(irp->f, "@saveErrRetAddr()"); -} - -static void ir_print_add_implicit_return_type(IrPrintSrc *irp, Stage1ZirInstAddImplicitReturnType *instruction) { - fprintf(irp->f, "@addImplicitReturnType("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_float_op(IrPrintSrc *irp, Stage1ZirInstFloatOp *instruction) { - fprintf(irp->f, "@%s(", float_un_op_to_name(instruction->fn_id)); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_float_op(IrPrintGen *irp, Stage1AirInstFloatOp *instruction) { - fprintf(irp->f, "@%s(", float_un_op_to_name(instruction->fn_id)); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_mul_add(IrPrintSrc *irp, Stage1ZirInstMulAdd *instruction) { - fprintf(irp->f, "@mulAdd("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op2); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op3); - fprintf(irp->f, ")"); -} - -static void ir_print_mul_add(IrPrintGen *irp, Stage1AirInstMulAdd *instruction) { - fprintf(irp->f, "@mulAdd("); - ir_print_other_inst_gen(irp, instruction->op1); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->op2); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->op3); - fprintf(irp->f, ")"); -} - -static void ir_print_decl_var_gen(IrPrintGen *irp, Stage1AirInstDeclVar *decl_var_instruction) { - ZigVar *var = decl_var_instruction->var; - const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; - const char *name = decl_var_instruction->var->name; - fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), - var->align_bytes); - - ir_print_other_inst_gen(irp, decl_var_instruction->var_ptr); -} - -static void ir_print_has_decl(IrPrintSrc *irp, Stage1ZirInstHasDecl *instruction) { - fprintf(irp->f, "@hasDecl("); - ir_print_other_inst_src(irp, instruction->container); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_undeclared_ident(IrPrintSrc *irp, Stage1ZirInstUndeclaredIdent *instruction) { - fprintf(irp->f, "@undeclaredIdent(%s)", buf_ptr(instruction->name)); -} - -static void ir_print_union_init_named_field(IrPrintSrc *irp, Stage1ZirInstUnionInitNamedField *instruction) { - fprintf(irp->f, "@unionInit("); - ir_print_other_inst_src(irp, instruction->union_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_result_loc); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_suspend_begin(IrPrintSrc *irp, Stage1ZirInstSuspendBegin *instruction) { - fprintf(irp->f, "@suspendBegin()"); -} - -static void ir_print_suspend_begin(IrPrintGen *irp, Stage1AirInstSuspendBegin *instruction) { - fprintf(irp->f, "@suspendBegin()"); -} - -static void ir_print_suspend_finish(IrPrintSrc *irp, Stage1ZirInstSuspendFinish *instruction) { - fprintf(irp->f, "@suspendFinish()"); -} - -static void ir_print_suspend_finish(IrPrintGen *irp, Stage1AirInstSuspendFinish *instruction) { - fprintf(irp->f, "@suspendFinish()"); -} - -static void ir_print_resume(IrPrintSrc *irp, Stage1ZirInstResume *instruction) { - fprintf(irp->f, "resume "); - ir_print_other_inst_src(irp, instruction->frame); -} - -static void ir_print_resume(IrPrintGen *irp, Stage1AirInstResume *instruction) { - fprintf(irp->f, "resume "); - ir_print_other_inst_gen(irp, instruction->frame); -} - -static void ir_print_await_src(IrPrintSrc *irp, Stage1ZirInstAwait *instruction) { - fprintf(irp->f, "@await("); - ir_print_other_inst_src(irp, instruction->frame); - fprintf(irp->f, ","); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_await_gen(IrPrintGen *irp, Stage1AirInstAwait *instruction) { - fprintf(irp->f, "@await("); - ir_print_other_inst_gen(irp, instruction->frame); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_begin(IrPrintSrc *irp, Stage1ZirInstSpillBegin *instruction) { - fprintf(irp->f, "@spillBegin("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_begin(IrPrintGen *irp, Stage1AirInstSpillBegin *instruction) { - fprintf(irp->f, "@spillBegin("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_end(IrPrintSrc *irp, Stage1ZirInstSpillEnd *instruction) { - fprintf(irp->f, "@spillEnd("); - ir_print_other_inst_src(irp, &instruction->begin->base); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_end(IrPrintGen *irp, Stage1AirInstSpillEnd *instruction) { - fprintf(irp->f, "@spillEnd("); - ir_print_other_inst_gen(irp, &instruction->begin->base); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_extract_elem(IrPrintGen *irp, Stage1AirInstVectorExtractElem *instruction) { - fprintf(irp->f, "@vectorExtractElem("); - ir_print_other_inst_gen(irp, instruction->vector); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool trailing) { - ir_print_prefix_src(irp, instruction, trailing); - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdReturn: - ir_print_return_src(irp, (Stage1ZirInstReturn *)instruction); - break; - case Stage1ZirInstIdConst: - ir_print_const(irp, (Stage1ZirInstConst *)instruction); - break; - case Stage1ZirInstIdBinOp: - ir_print_bin_op(irp, (Stage1ZirInstBinOp *)instruction); - break; - case Stage1ZirInstIdMergeErrSets: - ir_print_merge_err_sets(irp, (Stage1ZirInstMergeErrSets *)instruction); - break; - case Stage1ZirInstIdDeclVar: - ir_print_decl_var_src(irp, (Stage1ZirInstDeclVar *)instruction); - break; - case Stage1ZirInstIdCallExtra: - ir_print_call_extra(irp, (Stage1ZirInstCallExtra *)instruction); - break; - case Stage1ZirInstIdAsyncCallExtra: - ir_print_async_call_extra(irp, (Stage1ZirInstAsyncCallExtra *)instruction); - break; - case Stage1ZirInstIdCall: - ir_print_call_src(irp, (Stage1ZirInstCall *)instruction); - break; - case Stage1ZirInstIdCallArgs: - ir_print_call_args(irp, (Stage1ZirInstCallArgs *)instruction); - break; - case Stage1ZirInstIdUnOp: - ir_print_un_op(irp, (Stage1ZirInstUnOp *)instruction); - break; - case Stage1ZirInstIdCondBr: - ir_print_cond_br(irp, (Stage1ZirInstCondBr *)instruction); - break; - case Stage1ZirInstIdBr: - ir_print_br(irp, (Stage1ZirInstBr *)instruction); - break; - case Stage1ZirInstIdPhi: - ir_print_phi(irp, (Stage1ZirInstPhi *)instruction); - break; - case Stage1ZirInstIdContainerInitList: - ir_print_container_init_list(irp, (Stage1ZirInstContainerInitList *)instruction); - break; - case Stage1ZirInstIdContainerInitFields: - ir_print_container_init_fields(irp, (Stage1ZirInstContainerInitFields *)instruction); - break; - case Stage1ZirInstIdUnreachable: - ir_print_unreachable(irp, (Stage1ZirInstUnreachable *)instruction); - break; - case Stage1ZirInstIdElemPtr: - ir_print_elem_ptr(irp, (Stage1ZirInstElemPtr *)instruction); - break; - case Stage1ZirInstIdVarPtr: - ir_print_var_ptr(irp, (Stage1ZirInstVarPtr *)instruction); - break; - case Stage1ZirInstIdLoadPtr: - ir_print_load_ptr(irp, (Stage1ZirInstLoadPtr *)instruction); - break; - case Stage1ZirInstIdStorePtr: - ir_print_store_ptr(irp, (Stage1ZirInstStorePtr *)instruction); - break; - case Stage1ZirInstIdTypeOf: - ir_print_typeof(irp, (Stage1ZirInstTypeOf *)instruction); - break; - case Stage1ZirInstIdFieldPtr: - ir_print_field_ptr(irp, (Stage1ZirInstFieldPtr *)instruction); - break; - case Stage1ZirInstIdSetCold: - ir_print_set_cold(irp, (Stage1ZirInstSetCold *)instruction); - break; - case Stage1ZirInstIdSetRuntimeSafety: - ir_print_set_runtime_safety(irp, (Stage1ZirInstSetRuntimeSafety *)instruction); - break; - case Stage1ZirInstIdSetFloatMode: - ir_print_set_float_mode(irp, (Stage1ZirInstSetFloatMode *)instruction); - break; - case Stage1ZirInstIdArrayType: - ir_print_array_type(irp, (Stage1ZirInstArrayType *)instruction); - break; - case Stage1ZirInstIdSliceType: - ir_print_slice_type(irp, (Stage1ZirInstSliceType *)instruction); - break; - case Stage1ZirInstIdAnyFrameType: - ir_print_any_frame_type(irp, (Stage1ZirInstAnyFrameType *)instruction); - break; - case Stage1ZirInstIdAsm: - ir_print_asm_src(irp, (Stage1ZirInstAsm *)instruction); - break; - case Stage1ZirInstIdSizeOf: - ir_print_size_of(irp, (Stage1ZirInstSizeOf *)instruction); - break; - case Stage1ZirInstIdTestNonNull: - ir_print_test_non_null(irp, (Stage1ZirInstTestNonNull *)instruction); - break; - case Stage1ZirInstIdOptionalUnwrapPtr: - ir_print_optional_unwrap_ptr(irp, (Stage1ZirInstOptionalUnwrapPtr *)instruction); - break; - case Stage1ZirInstIdPopCount: - ir_print_pop_count(irp, (Stage1ZirInstPopCount *)instruction); - break; - case Stage1ZirInstIdCtz: - ir_print_ctz(irp, (Stage1ZirInstCtz *)instruction); - break; - case Stage1ZirInstIdBswap: - ir_print_bswap(irp, (Stage1ZirInstBswap *)instruction); - break; - case Stage1ZirInstIdBitReverse: - ir_print_bit_reverse(irp, (Stage1ZirInstBitReverse *)instruction); - break; - case Stage1ZirInstIdSwitchBr: - ir_print_switch_br(irp, (Stage1ZirInstSwitchBr *)instruction); - break; - case Stage1ZirInstIdSwitchVar: - ir_print_switch_var(irp, (Stage1ZirInstSwitchVar *)instruction); - break; - case Stage1ZirInstIdSwitchElseVar: - ir_print_switch_else_var(irp, (Stage1ZirInstSwitchElseVar *)instruction); - break; - case Stage1ZirInstIdSwitchTarget: - ir_print_switch_target(irp, (Stage1ZirInstSwitchTarget *)instruction); - break; - case Stage1ZirInstIdImport: - ir_print_import(irp, (Stage1ZirInstImport *)instruction); - break; - case Stage1ZirInstIdRef: - ir_print_ref(irp, (Stage1ZirInstRef *)instruction); - break; - case Stage1ZirInstIdCompileErr: - ir_print_compile_err(irp, (Stage1ZirInstCompileErr *)instruction); - break; - case Stage1ZirInstIdCompileLog: - ir_print_compile_log(irp, (Stage1ZirInstCompileLog *)instruction); - break; - case Stage1ZirInstIdErrName: - ir_print_err_name(irp, (Stage1ZirInstErrName *)instruction); - break; - case Stage1ZirInstIdCImport: - ir_print_c_import(irp, (Stage1ZirInstCImport *)instruction); - break; - case Stage1ZirInstIdCInclude: - ir_print_c_include(irp, (Stage1ZirInstCInclude *)instruction); - break; - case Stage1ZirInstIdCDefine: - ir_print_c_define(irp, (Stage1ZirInstCDefine *)instruction); - break; - case Stage1ZirInstIdCUndef: - ir_print_c_undef(irp, (Stage1ZirInstCUndef *)instruction); - break; - case Stage1ZirInstIdEmbedFile: - ir_print_embed_file(irp, (Stage1ZirInstEmbedFile *)instruction); - break; - case Stage1ZirInstIdCmpxchg: - ir_print_cmpxchg_src(irp, (Stage1ZirInstCmpxchg *)instruction); - break; - case Stage1ZirInstIdFence: - ir_print_fence(irp, (Stage1ZirInstFence *)instruction); - break; - case Stage1ZirInstIdReduce: - ir_print_reduce(irp, (Stage1ZirInstReduce *)instruction); - break; - case Stage1ZirInstIdTruncate: - ir_print_truncate(irp, (Stage1ZirInstTruncate *)instruction); - break; - case Stage1ZirInstIdIntCast: - ir_print_int_cast(irp, (Stage1ZirInstIntCast *)instruction); - break; - case Stage1ZirInstIdFloatCast: - ir_print_float_cast(irp, (Stage1ZirInstFloatCast *)instruction); - break; - case Stage1ZirInstIdErrSetCast: - ir_print_err_set_cast(irp, (Stage1ZirInstErrSetCast *)instruction); - break; - case Stage1ZirInstIdIntToFloat: - ir_print_int_to_float(irp, (Stage1ZirInstIntToFloat *)instruction); - break; - case Stage1ZirInstIdFloatToInt: - ir_print_float_to_int(irp, (Stage1ZirInstFloatToInt *)instruction); - break; - case Stage1ZirInstIdBoolToInt: - ir_print_bool_to_int(irp, (Stage1ZirInstBoolToInt *)instruction); - break; - case Stage1ZirInstIdVectorType: - ir_print_vector_type(irp, (Stage1ZirInstVectorType *)instruction); - break; - case Stage1ZirInstIdShuffleVector: - ir_print_shuffle_vector(irp, (Stage1ZirInstShuffleVector *)instruction); - break; - case Stage1ZirInstIdSelect: - ir_print_select(irp, (Stage1ZirInstSelect *)instruction); - break; - case Stage1ZirInstIdSplat: - ir_print_splat_src(irp, (Stage1ZirInstSplat *)instruction); - break; - case Stage1ZirInstIdBoolNot: - ir_print_bool_not(irp, (Stage1ZirInstBoolNot *)instruction); - break; - case Stage1ZirInstIdMemset: - ir_print_memset(irp, (Stage1ZirInstMemset *)instruction); - break; - case Stage1ZirInstIdMemcpy: - ir_print_memcpy(irp, (Stage1ZirInstMemcpy *)instruction); - break; - case Stage1ZirInstIdSlice: - ir_print_slice_src(irp, (Stage1ZirInstSlice *)instruction); - break; - case Stage1ZirInstIdBreakpoint: - ir_print_breakpoint(irp, (Stage1ZirInstBreakpoint *)instruction); - break; - case Stage1ZirInstIdReturnAddress: - ir_print_return_address(irp, (Stage1ZirInstReturnAddress *)instruction); - break; - case Stage1ZirInstIdFrameAddress: - ir_print_frame_address(irp, (Stage1ZirInstFrameAddress *)instruction); - break; - case Stage1ZirInstIdFrameHandle: - ir_print_handle(irp, (Stage1ZirInstFrameHandle *)instruction); - break; - case Stage1ZirInstIdFrameType: - ir_print_frame_type(irp, (Stage1ZirInstFrameType *)instruction); - break; - case Stage1ZirInstIdFrameSize: - ir_print_frame_size_src(irp, (Stage1ZirInstFrameSize *)instruction); - break; - case Stage1ZirInstIdAlignOf: - ir_print_align_of(irp, (Stage1ZirInstAlignOf *)instruction); - break; - case Stage1ZirInstIdOverflowOp: - ir_print_overflow_op(irp, (Stage1ZirInstOverflowOp *)instruction); - break; - case Stage1ZirInstIdTestErr: - ir_print_test_err_src(irp, (Stage1ZirInstTestErr *)instruction); - break; - case Stage1ZirInstIdUnwrapErrCode: - ir_print_unwrap_err_code(irp, (Stage1ZirInstUnwrapErrCode *)instruction); - break; - case Stage1ZirInstIdUnwrapErrPayload: - ir_print_unwrap_err_payload(irp, (Stage1ZirInstUnwrapErrPayload *)instruction); - break; - case Stage1ZirInstIdFnProto: - ir_print_fn_proto(irp, (Stage1ZirInstFnProto *)instruction); - break; - case Stage1ZirInstIdTestComptime: - ir_print_test_comptime(irp, (Stage1ZirInstTestComptime *)instruction); - break; - case Stage1ZirInstIdPtrCast: - ir_print_ptr_cast_src(irp, (Stage1ZirInstPtrCast *)instruction); - break; - case Stage1ZirInstIdBitCast: - ir_print_bit_cast_src(irp, (Stage1ZirInstBitCast *)instruction); - break; - case Stage1ZirInstIdPtrToInt: - ir_print_ptr_to_int(irp, (Stage1ZirInstPtrToInt *)instruction); - break; - case Stage1ZirInstIdIntToPtr: - ir_print_int_to_ptr(irp, (Stage1ZirInstIntToPtr *)instruction); - break; - case Stage1ZirInstIdIntToEnum: - ir_print_int_to_enum(irp, (Stage1ZirInstIntToEnum *)instruction); - break; - case Stage1ZirInstIdIntToErr: - ir_print_int_to_err(irp, (Stage1ZirInstIntToErr *)instruction); - break; - case Stage1ZirInstIdErrToInt: - ir_print_err_to_int(irp, (Stage1ZirInstErrToInt *)instruction); - break; - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - ir_print_check_switch_prongs(irp, (Stage1ZirInstCheckSwitchProngs *)instruction, false); - break; - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - ir_print_check_switch_prongs(irp, (Stage1ZirInstCheckSwitchProngs *)instruction, true); - break; - case Stage1ZirInstIdCheckStatementIsVoid: - ir_print_check_statement_is_void(irp, (Stage1ZirInstCheckStatementIsVoid *)instruction); - break; - case Stage1ZirInstIdTypeName: - ir_print_type_name(irp, (Stage1ZirInstTypeName *)instruction); - break; - case Stage1ZirInstIdTagName: - ir_print_tag_name(irp, (Stage1ZirInstTagName *)instruction); - break; - case Stage1ZirInstIdPtrType: - ir_print_ptr_type(irp, (Stage1ZirInstPtrType *)instruction); - break; - case Stage1ZirInstIdPtrTypeSimple: - ir_print_ptr_type_simple(irp, (Stage1ZirInstPtrTypeSimple *)instruction, false); - break; - case Stage1ZirInstIdPtrTypeSimpleConst: - ir_print_ptr_type_simple(irp, (Stage1ZirInstPtrTypeSimple *)instruction, true); - break; - case Stage1ZirInstIdDeclRef: - ir_print_decl_ref(irp, (Stage1ZirInstDeclRef *)instruction); - break; - case Stage1ZirInstIdPanic: - ir_print_panic(irp, (Stage1ZirInstPanic *)instruction); - break; - case Stage1ZirInstIdFieldParentPtr: - ir_print_field_parent_ptr(irp, (Stage1ZirInstFieldParentPtr *)instruction); - break; - case Stage1ZirInstIdOffsetOf: - ir_print_offset_of(irp, (Stage1ZirInstOffsetOf *)instruction); - break; - case Stage1ZirInstIdBitOffsetOf: - ir_print_bit_offset_of(irp, (Stage1ZirInstBitOffsetOf *)instruction); - break; - case Stage1ZirInstIdTypeInfo: - ir_print_type_info(irp, (Stage1ZirInstTypeInfo *)instruction); - break; - case Stage1ZirInstIdType: - ir_print_type(irp, (Stage1ZirInstType *)instruction); - break; - case Stage1ZirInstIdHasField: - ir_print_has_field(irp, (Stage1ZirInstHasField *)instruction); - break; - case Stage1ZirInstIdSetEvalBranchQuota: - ir_print_set_eval_branch_quota(irp, (Stage1ZirInstSetEvalBranchQuota *)instruction); - break; - case Stage1ZirInstIdAlignCast: - ir_print_align_cast(irp, (Stage1ZirInstAlignCast *)instruction); - break; - case Stage1ZirInstIdImplicitCast: - ir_print_implicit_cast(irp, (Stage1ZirInstImplicitCast *)instruction); - break; - case Stage1ZirInstIdResolveResult: - ir_print_resolve_result(irp, (Stage1ZirInstResolveResult *)instruction); - break; - case Stage1ZirInstIdResetResult: - ir_print_reset_result(irp, (Stage1ZirInstResetResult *)instruction); - break; - case Stage1ZirInstIdSetAlignStack: - ir_print_set_align_stack(irp, (Stage1ZirInstSetAlignStack *)instruction); - break; - case Stage1ZirInstIdArgTypeAllowVarFalse: - ir_print_arg_type(irp, (Stage1ZirInstArgType *)instruction, false); - break; - case Stage1ZirInstIdArgTypeAllowVarTrue: - ir_print_arg_type(irp, (Stage1ZirInstArgType *)instruction, true); - break; - case Stage1ZirInstIdExport: - ir_print_export(irp, (Stage1ZirInstExport *)instruction); - break; - case Stage1ZirInstIdExtern: - ir_print_extern(irp, (Stage1ZirInstExtern*)instruction); - break; - case Stage1ZirInstIdErrorReturnTrace: - ir_print_error_return_trace(irp, (Stage1ZirInstErrorReturnTrace *)instruction); - break; - case Stage1ZirInstIdErrorUnion: - ir_print_error_union(irp, (Stage1ZirInstErrorUnion *)instruction); - break; - case Stage1ZirInstIdAtomicRmw: - ir_print_atomic_rmw(irp, (Stage1ZirInstAtomicRmw *)instruction); - break; - case Stage1ZirInstIdSaveErrRetAddr: - ir_print_save_err_ret_addr(irp, (Stage1ZirInstSaveErrRetAddr *)instruction); - break; - case Stage1ZirInstIdAddImplicitReturnType: - ir_print_add_implicit_return_type(irp, (Stage1ZirInstAddImplicitReturnType *)instruction); - break; - case Stage1ZirInstIdFloatOp: - ir_print_float_op(irp, (Stage1ZirInstFloatOp *)instruction); - break; - case Stage1ZirInstIdMulAdd: - ir_print_mul_add(irp, (Stage1ZirInstMulAdd *)instruction); - break; - case Stage1ZirInstIdAtomicLoad: - ir_print_atomic_load(irp, (Stage1ZirInstAtomicLoad *)instruction); - break; - case Stage1ZirInstIdAtomicStore: - ir_print_atomic_store(irp, (Stage1ZirInstAtomicStore *)instruction); - break; - case Stage1ZirInstIdEnumToInt: - ir_print_enum_to_int(irp, (Stage1ZirInstEnumToInt *)instruction); - break; - case Stage1ZirInstIdCheckRuntimeScope: - ir_print_check_runtime_scope(irp, (Stage1ZirInstCheckRuntimeScope *)instruction); - break; - case Stage1ZirInstIdHasDecl: - ir_print_has_decl(irp, (Stage1ZirInstHasDecl *)instruction); - break; - case Stage1ZirInstIdUndeclaredIdent: - ir_print_undeclared_ident(irp, (Stage1ZirInstUndeclaredIdent *)instruction); - break; - case Stage1ZirInstIdAlloca: - ir_print_alloca_src(irp, (Stage1ZirInstAlloca *)instruction); - break; - case Stage1ZirInstIdEndExpr: - ir_print_end_expr(irp, (Stage1ZirInstEndExpr *)instruction); - break; - case Stage1ZirInstIdUnionInitNamedField: - ir_print_union_init_named_field(irp, (Stage1ZirInstUnionInitNamedField *)instruction); - break; - case Stage1ZirInstIdSuspendBegin: - ir_print_suspend_begin(irp, (Stage1ZirInstSuspendBegin *)instruction); - break; - case Stage1ZirInstIdSuspendFinish: - ir_print_suspend_finish(irp, (Stage1ZirInstSuspendFinish *)instruction); - break; - case Stage1ZirInstIdResume: - ir_print_resume(irp, (Stage1ZirInstResume *)instruction); - break; - case Stage1ZirInstIdAwait: - ir_print_await_src(irp, (Stage1ZirInstAwait *)instruction); - break; - case Stage1ZirInstIdSpillBegin: - ir_print_spill_begin(irp, (Stage1ZirInstSpillBegin *)instruction); - break; - case Stage1ZirInstIdSpillEnd: - ir_print_spill_end(irp, (Stage1ZirInstSpillEnd *)instruction); - break; - case Stage1ZirInstIdClz: - ir_print_clz(irp, (Stage1ZirInstClz *)instruction); - break; - case Stage1ZirInstIdWasmMemorySize: - ir_print_wasm_memory_size(irp, (Stage1ZirInstWasmMemorySize *)instruction); - break; - case Stage1ZirInstIdWasmMemoryGrow: - ir_print_wasm_memory_grow(irp, (Stage1ZirInstWasmMemoryGrow *)instruction); - break; - case Stage1ZirInstIdSrc: - ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction); - break; - case Stage1ZirInstIdPrefetch: - ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction); - break; - case Stage1ZirInstIdAddrSpaceCast: - ir_print_addrspace_cast(irp, (Stage1ZirInstAddrSpaceCast *)instruction); - break; - } - fprintf(irp->f, "\n"); -} - -static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool trailing) { - ir_print_prefix_gen(irp, instruction, trailing); - switch (instruction->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdReturn: - ir_print_return_gen(irp, (Stage1AirInstReturn *)instruction); - break; - case Stage1AirInstIdConst: - ir_print_const(irp, (Stage1AirInstConst *)instruction); - break; - case Stage1AirInstIdBinOp: - ir_print_bin_op(irp, (Stage1AirInstBinOp *)instruction); - break; - case Stage1AirInstIdDeclVar: - ir_print_decl_var_gen(irp, (Stage1AirInstDeclVar *)instruction); - break; - case Stage1AirInstIdCast: - ir_print_cast(irp, (Stage1AirInstCast *)instruction); - break; - case Stage1AirInstIdCall: - ir_print_call_gen(irp, (Stage1AirInstCall *)instruction); - break; - case Stage1AirInstIdCondBr: - ir_print_cond_br(irp, (Stage1AirInstCondBr *)instruction); - break; - case Stage1AirInstIdBr: - ir_print_br(irp, (Stage1AirInstBr *)instruction); - break; - case Stage1AirInstIdPhi: - ir_print_phi(irp, (Stage1AirInstPhi *)instruction); - break; - case Stage1AirInstIdUnreachable: - ir_print_unreachable(irp, (Stage1AirInstUnreachable *)instruction); - break; - case Stage1AirInstIdElemPtr: - ir_print_elem_ptr(irp, (Stage1AirInstElemPtr *)instruction); - break; - case Stage1AirInstIdVarPtr: - ir_print_var_ptr(irp, (Stage1AirInstVarPtr *)instruction); - break; - case Stage1AirInstIdReturnPtr: - ir_print_return_ptr(irp, (Stage1AirInstReturnPtr *)instruction); - break; - case Stage1AirInstIdLoadPtr: - ir_print_load_ptr_gen(irp, (Stage1AirInstLoadPtr *)instruction); - break; - case Stage1AirInstIdStorePtr: - ir_print_store_ptr(irp, (Stage1AirInstStorePtr *)instruction); - break; - case Stage1AirInstIdStructFieldPtr: - ir_print_struct_field_ptr(irp, (Stage1AirInstStructFieldPtr *)instruction); - break; - case Stage1AirInstIdUnionFieldPtr: - ir_print_union_field_ptr(irp, (Stage1AirInstUnionFieldPtr *)instruction); - break; - case Stage1AirInstIdAsm: - ir_print_asm_gen(irp, (Stage1AirInstAsm *)instruction); - break; - case Stage1AirInstIdTestNonNull: - ir_print_test_non_null(irp, (Stage1AirInstTestNonNull *)instruction); - break; - case Stage1AirInstIdOptionalUnwrapPtr: - ir_print_optional_unwrap_ptr(irp, (Stage1AirInstOptionalUnwrapPtr *)instruction); - break; - case Stage1AirInstIdPopCount: - ir_print_pop_count(irp, (Stage1AirInstPopCount *)instruction); - break; - case Stage1AirInstIdClz: - ir_print_clz(irp, (Stage1AirInstClz *)instruction); - break; - case Stage1AirInstIdCtz: - ir_print_ctz(irp, (Stage1AirInstCtz *)instruction); - break; - case Stage1AirInstIdBswap: - ir_print_bswap(irp, (Stage1AirInstBswap *)instruction); - break; - case Stage1AirInstIdBitReverse: - ir_print_bit_reverse(irp, (Stage1AirInstBitReverse *)instruction); - break; - case Stage1AirInstIdSwitchBr: - ir_print_switch_br(irp, (Stage1AirInstSwitchBr *)instruction); - break; - case Stage1AirInstIdUnionTag: - ir_print_union_tag(irp, (Stage1AirInstUnionTag *)instruction); - break; - case Stage1AirInstIdRef: - ir_print_ref_gen(irp, (Stage1AirInstRef *)instruction); - break; - case Stage1AirInstIdErrName: - ir_print_err_name(irp, (Stage1AirInstErrName *)instruction); - break; - case Stage1AirInstIdCmpxchg: - ir_print_cmpxchg_gen(irp, (Stage1AirInstCmpxchg *)instruction); - break; - case Stage1AirInstIdFence: - ir_print_fence(irp, (Stage1AirInstFence *)instruction); - break; - case Stage1AirInstIdReduce: - ir_print_reduce(irp, (Stage1AirInstReduce *)instruction); - break; - case Stage1AirInstIdTruncate: - ir_print_truncate(irp, (Stage1AirInstTruncate *)instruction); - break; - case Stage1AirInstIdShuffleVector: - ir_print_shuffle_vector(irp, (Stage1AirInstShuffleVector *)instruction); - break; - case Stage1AirInstIdSelect: - ir_print_select(irp, (Stage1AirInstSelect *)instruction); - break; - case Stage1AirInstIdSplat: - ir_print_splat_gen(irp, (Stage1AirInstSplat *)instruction); - break; - case Stage1AirInstIdBoolNot: - ir_print_bool_not(irp, (Stage1AirInstBoolNot *)instruction); - break; - case Stage1AirInstIdMemset: - ir_print_memset(irp, (Stage1AirInstMemset *)instruction); - break; - case Stage1AirInstIdMemcpy: - ir_print_memcpy(irp, (Stage1AirInstMemcpy *)instruction); - break; - case Stage1AirInstIdSlice: - ir_print_slice_gen(irp, (Stage1AirInstSlice *)instruction); - break; - case Stage1AirInstIdBreakpoint: - ir_print_breakpoint(irp, (Stage1AirInstBreakpoint *)instruction); - break; - case Stage1AirInstIdReturnAddress: - ir_print_return_address(irp, (Stage1AirInstReturnAddress *)instruction); - break; - case Stage1AirInstIdFrameAddress: - ir_print_frame_address(irp, (Stage1AirInstFrameAddress *)instruction); - break; - case Stage1AirInstIdFrameHandle: - ir_print_handle(irp, (Stage1AirInstFrameHandle *)instruction); - break; - case Stage1AirInstIdFrameSize: - ir_print_frame_size_gen(irp, (Stage1AirInstFrameSize *)instruction); - break; - case Stage1AirInstIdOverflowOp: - ir_print_overflow_op(irp, (Stage1AirInstOverflowOp *)instruction); - break; - case Stage1AirInstIdTestErr: - ir_print_test_err_gen(irp, (Stage1AirInstTestErr *)instruction); - break; - case Stage1AirInstIdUnwrapErrCode: - ir_print_unwrap_err_code(irp, (Stage1AirInstUnwrapErrCode *)instruction); - break; - case Stage1AirInstIdUnwrapErrPayload: - ir_print_unwrap_err_payload(irp, (Stage1AirInstUnwrapErrPayload *)instruction); - break; - case Stage1AirInstIdOptionalWrap: - ir_print_optional_wrap(irp, (Stage1AirInstOptionalWrap *)instruction); - break; - case Stage1AirInstIdErrWrapCode: - ir_print_err_wrap_code(irp, (Stage1AirInstErrWrapCode *)instruction); - break; - case Stage1AirInstIdErrWrapPayload: - ir_print_err_wrap_payload(irp, (Stage1AirInstErrWrapPayload *)instruction); - break; - case Stage1AirInstIdPtrCast: - ir_print_ptr_cast_gen(irp, (Stage1AirInstPtrCast *)instruction); - break; - case Stage1AirInstIdBitCast: - ir_print_bit_cast_gen(irp, (Stage1AirInstBitCast *)instruction); - break; - case Stage1AirInstIdWidenOrShorten: - ir_print_widen_or_shorten(irp, (Stage1AirInstWidenOrShorten *)instruction); - break; - case Stage1AirInstIdPtrToInt: - ir_print_ptr_to_int(irp, (Stage1AirInstPtrToInt *)instruction); - break; - case Stage1AirInstIdIntToPtr: - ir_print_int_to_ptr(irp, (Stage1AirInstIntToPtr *)instruction); - break; - case Stage1AirInstIdIntToEnum: - ir_print_int_to_enum(irp, (Stage1AirInstIntToEnum *)instruction); - break; - case Stage1AirInstIdIntToErr: - ir_print_int_to_err(irp, (Stage1AirInstIntToErr *)instruction); - break; - case Stage1AirInstIdErrToInt: - ir_print_err_to_int(irp, (Stage1AirInstErrToInt *)instruction); - break; - case Stage1AirInstIdTagName: - ir_print_tag_name(irp, (Stage1AirInstTagName *)instruction); - break; - case Stage1AirInstIdPanic: - ir_print_panic(irp, (Stage1AirInstPanic *)instruction); - break; - case Stage1AirInstIdFieldParentPtr: - ir_print_field_parent_ptr(irp, (Stage1AirInstFieldParentPtr *)instruction); - break; - case Stage1AirInstIdAlignCast: - ir_print_align_cast(irp, (Stage1AirInstAlignCast *)instruction); - break; - case Stage1AirInstIdErrorReturnTrace: - ir_print_error_return_trace(irp, (Stage1AirInstErrorReturnTrace *)instruction); - break; - case Stage1AirInstIdAtomicRmw: - ir_print_atomic_rmw(irp, (Stage1AirInstAtomicRmw *)instruction); - break; - case Stage1AirInstIdSaveErrRetAddr: - ir_print_save_err_ret_addr(irp, (Stage1AirInstSaveErrRetAddr *)instruction); - break; - case Stage1AirInstIdFloatOp: - ir_print_float_op(irp, (Stage1AirInstFloatOp *)instruction); - break; - case Stage1AirInstIdMulAdd: - ir_print_mul_add(irp, (Stage1AirInstMulAdd *)instruction); - break; - case Stage1AirInstIdAtomicLoad: - ir_print_atomic_load(irp, (Stage1AirInstAtomicLoad *)instruction); - break; - case Stage1AirInstIdAtomicStore: - ir_print_atomic_store(irp, (Stage1AirInstAtomicStore *)instruction); - break; - case Stage1AirInstIdArrayToVector: - ir_print_array_to_vector(irp, (Stage1AirInstArrayToVector *)instruction); - break; - case Stage1AirInstIdVectorToArray: - ir_print_vector_to_array(irp, (Stage1AirInstVectorToArray *)instruction); - break; - case Stage1AirInstIdPtrOfArrayToSlice: - ir_print_ptr_of_array_to_slice(irp, (Stage1AirInstPtrOfArrayToSlice *)instruction); - break; - case Stage1AirInstIdAssertZero: - ir_print_assert_zero(irp, (Stage1AirInstAssertZero *)instruction); - break; - case Stage1AirInstIdAssertNonNull: - ir_print_assert_non_null(irp, (Stage1AirInstAssertNonNull *)instruction); - break; - case Stage1AirInstIdAlloca: - ir_print_alloca_gen(irp, (Stage1AirInstAlloca *)instruction); - break; - case Stage1AirInstIdSuspendBegin: - ir_print_suspend_begin(irp, (Stage1AirInstSuspendBegin *)instruction); - break; - case Stage1AirInstIdSuspendFinish: - ir_print_suspend_finish(irp, (Stage1AirInstSuspendFinish *)instruction); - break; - case Stage1AirInstIdResume: - ir_print_resume(irp, (Stage1AirInstResume *)instruction); - break; - case Stage1AirInstIdAwait: - ir_print_await_gen(irp, (Stage1AirInstAwait *)instruction); - break; - case Stage1AirInstIdSpillBegin: - ir_print_spill_begin(irp, (Stage1AirInstSpillBegin *)instruction); - break; - case Stage1AirInstIdSpillEnd: - ir_print_spill_end(irp, (Stage1AirInstSpillEnd *)instruction); - break; - case Stage1AirInstIdVectorExtractElem: - ir_print_vector_extract_elem(irp, (Stage1AirInstVectorExtractElem *)instruction); - break; - case Stage1AirInstIdVectorStoreElem: - ir_print_vector_store_elem(irp, (Stage1AirInstVectorStoreElem *)instruction); - break; - case Stage1AirInstIdBinaryNot: - ir_print_binary_not(irp, (Stage1AirInstBinaryNot *)instruction); - break; - case Stage1AirInstIdNegation: - ir_print_negation(irp, (Stage1AirInstNegation *)instruction); - break; - case Stage1AirInstIdWasmMemorySize: - ir_print_wasm_memory_size(irp, (Stage1AirInstWasmMemorySize *)instruction); - break; - case Stage1AirInstIdWasmMemoryGrow: - ir_print_wasm_memory_grow(irp, (Stage1AirInstWasmMemoryGrow *)instruction); - break; - case Stage1AirInstIdExtern: - ir_print_extern(irp, (Stage1AirInstExtern *)instruction); - break; - case Stage1AirInstIdPrefetch: - ir_print_prefetch(irp, (Stage1AirInstPrefetch *)instruction); - break; - - } - fprintf(irp->f, "\n"); -} - -static void irp_print_basic_block_src(IrPrintSrc *irp, Stage1ZirBasicBlock *current_block) { - fprintf(irp->f, "%s_%" PRIu32 ":\n", current_block->name_hint, current_block->debug_id); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1ZirInst *instruction = current_block->instruction_list.at(instr_i); - ir_print_inst_src(irp, instruction, false); - } -} - -static void irp_print_basic_block_gen(IrPrintGen *irp, Stage1AirBasicBlock *current_block) { - fprintf(irp->f, "%s_%" PRIu32 ":\n", current_block->name_hint, current_block->debug_id); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = current_block->instruction_list.at(instr_i); - irp->printed.put(instruction, 0); - irp->pending.clear(); - ir_print_inst_gen(irp, instruction, false); - for (size_t j = 0; j < irp->pending.length; ++j) - ir_print_inst_gen(irp, irp->pending.at(j), true); - } -} - -void ir_print_basic_block_src(CodeGen *codegen, FILE *f, Stage1ZirBasicBlock *bb, int indent_size) { - IrPrintSrc ir_print = {}; - ir_print.codegen = codegen; - ir_print.f = f; - ir_print.indent = indent_size; - ir_print.indent_size = indent_size; - - irp_print_basic_block_src(&ir_print, bb); -} - -void ir_print_basic_block_gen(CodeGen *codegen, FILE *f, Stage1AirBasicBlock *bb, int indent_size) { - IrPrintGen ir_print = {}; - ir_print.codegen = codegen; - ir_print.f = f; - ir_print.indent = indent_size; - ir_print.indent_size = indent_size; - ir_print.printed = {}; - ir_print.printed.init(64); - ir_print.pending = {}; - - irp_print_basic_block_gen(&ir_print, bb); - - ir_print.pending.deinit(); - ir_print.printed.deinit(); -} - -void ir_print_src(CodeGen *codegen, FILE *f, Stage1Zir *executable, int indent_size) { - IrPrintSrc ir_print = {}; - IrPrintSrc *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - - for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { - irp_print_basic_block_src(irp, executable->basic_block_list.at(bb_i)); - } -} - -void ir_print_gen(CodeGen *codegen, FILE *f, Stage1Air *executable, int indent_size) { - IrPrintGen ir_print = {}; - IrPrintGen *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - irp->printed = {}; - irp->printed.init(64); - irp->pending = {}; - - for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { - irp_print_basic_block_gen(irp, executable->basic_block_list.at(bb_i)); - } - - irp->pending.deinit(); - irp->printed.deinit(); -} - -void ir_print_inst_src(CodeGen *codegen, FILE *f, Stage1ZirInst *instruction, int indent_size) { - IrPrintSrc ir_print = {}; - IrPrintSrc *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - - ir_print_inst_src(irp, instruction, false); -} - -void ir_print_inst_gen(CodeGen *codegen, FILE *f, Stage1AirInst *instruction, int indent_size) { - IrPrintGen ir_print = {}; - IrPrintGen *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - irp->printed = {}; - irp->printed.init(4); - irp->pending = {}; - - ir_print_inst_gen(irp, instruction, false); -} - -void Stage1ZirInst::dump() { - Stage1ZirInst *inst = this; - inst->src(); - if (inst->scope == nullptr) { - fprintf(stderr, "(null scope)\n"); - } else { - ir_print_inst_src(inst->scope->codegen, stderr, inst, 0); - fprintf(stderr, "-> "); - ir_print_inst_gen(inst->scope->codegen, stderr, inst->child, 0); - } -} diff --git a/src/stage1/ir_print.hpp b/src/stage1/ir_print.hpp deleted file mode 100644 index 1baddc5bd924..000000000000 --- a/src/stage1/ir_print.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_IR_PRINT_HPP -#define ZIG_IR_PRINT_HPP - -#include "all_types.hpp" - -#include - -void ir_print_src(CodeGen *codegen, FILE *f, Stage1Zir *executable, int indent_size); -void ir_print_gen(CodeGen *codegen, FILE *f, Stage1Air *executable, int indent_size); -void ir_print_inst_src(CodeGen *codegen, FILE *f, Stage1ZirInst *inst, int indent_size); -void ir_print_inst_gen(CodeGen *codegen, FILE *f, Stage1AirInst *inst, int indent_size); -void ir_print_basic_block_src(CodeGen *codegen, FILE *f, Stage1ZirBasicBlock *bb, int indent_size); -void ir_print_basic_block_gen(CodeGen *codegen, FILE *f, Stage1AirBasicBlock *bb, int indent_size); - -const char* ir_inst_src_type_str(Stage1ZirInstId id); -const char* ir_inst_gen_type_str(Stage1AirInstId id); - -#endif diff --git a/src/stage1/list.hpp b/src/stage1/list.hpp deleted file mode 100644 index 803a2514371d..000000000000 --- a/src/stage1/list.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_LIST_HPP -#define ZIG_LIST_HPP - -#include "util.hpp" - -template -struct ZigList { - void deinit() { - heap::c_allocator.deallocate(items, capacity); - } - void append(const T& item) { - ensure_capacity(length + 1); - items[length++] = item; - } - void append_assuming_capacity(const T& item) { - items[length++] = item; - } - // remember that the pointer to this item is invalid after you - // modify the length of the list - const T & at(size_t index) const { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - T & at(size_t index) { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - T pop() { - assert(length >= 1); - return items[--length]; - } - - T *add_one() { - resize(length + 1); - return &last(); - } - - const T & last() const { - assert(length >= 1); - return items[length - 1]; - } - - T & last() { - assert(length >= 1); - return items[length - 1]; - } - - void resize(size_t new_length) { - assert(new_length != SIZE_MAX); - ensure_capacity(new_length); - length = new_length; - } - - void clear() { - length = 0; - } - - void ensure_capacity(size_t new_capacity) { - if (capacity >= new_capacity) - return; - - size_t better_capacity = capacity; - do { - better_capacity = better_capacity * 5 / 2 + 8; - } while (better_capacity < new_capacity); - - items = heap::c_allocator.reallocate_nonzero(items, capacity, better_capacity); - capacity = better_capacity; - } - - T swap_remove(size_t index) { - if (length - 1 == index) return pop(); - - assert(index != SIZE_MAX); - assert(index < length); - - T old_item = items[index]; - items[index] = pop(); - return old_item; - } - - T *items; - size_t length; - size_t capacity; -}; - -#endif diff --git a/src/stage1/mem.cpp b/src/stage1/mem.cpp deleted file mode 100644 index 5931c38e6e52..000000000000 --- a/src/stage1/mem.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "mem.hpp" -#include "heap.hpp" - -namespace mem { - -void init() { - heap::bootstrap_allocator_state.init("heap::bootstrap_allocator"); - heap::c_allocator_state.init("heap::c_allocator"); -} - -void deinit() { - heap::c_allocator_state.deinit(); - heap::bootstrap_allocator_state.deinit(); -} - -} // namespace mem diff --git a/src/stage1/mem.hpp b/src/stage1/mem.hpp deleted file mode 100644 index bf732412e4be..000000000000 --- a/src/stage1/mem.hpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_HPP -#define ZIG_MEM_HPP - -#include -#include -#include - -#include "util_base.hpp" -#include "mem_type_info.hpp" - -// -// -- Memory Allocation General Notes -- -// -// `heap::c_allocator` is the preferred general allocator. -// -// `heap::bootstrap_allocator` is an implementation detail for use -// by allocators themselves when incidental heap may be required for -// profiling and statistics. It breaks the infinite recursion cycle. -// -// `mem::os` contains a raw wrapper for system malloc API used in -// preference to calling ::{malloc, free, calloc, realloc} directly. -// This isolates usage and helps with audits: -// -// mem::os::malloc -// mem::os::free -// mem::os::calloc -// mem::os::realloc -// -namespace mem { - -// initialize mem module before any use -void init(); - -// deinitialize mem module to free memory and print report -void deinit(); - -// isolate system/libc allocators -namespace os { - -ATTRIBUTE_RETURNS_NOALIAS -inline void *malloc(size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (size == 0) - return nullptr; -#endif - auto ptr = ::malloc(size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -inline void free(void *ptr) { - ::free(ptr); -} - -ATTRIBUTE_RETURNS_NOALIAS -inline void *calloc(size_t count, size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (count == 0 || size == 0) - return nullptr; -#endif - auto ptr = ::calloc(count, size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -inline void *realloc(void *old_ptr, size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (old_ptr == nullptr && size == 0) - return nullptr; -#endif - auto ptr = ::realloc(old_ptr, size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -} // namespace os - -struct Allocator { - virtual void destruct(Allocator *allocator) = 0; - - template ATTRIBUTE_RETURNS_NOALIAS - T *allocate(size_t count) { - return reinterpret_cast(this->internal_allocate(TypeInfo::make(), count)); - } - - template ATTRIBUTE_RETURNS_NOALIAS - T *allocate_nonzero(size_t count) { - return reinterpret_cast(this->internal_allocate_nonzero(TypeInfo::make(), count)); - } - - template - T *reallocate(T *old_ptr, size_t old_count, size_t new_count) { - return reinterpret_cast(this->internal_reallocate(TypeInfo::make(), old_ptr, old_count, new_count)); - } - - template - T *reallocate_nonzero(T *old_ptr, size_t old_count, size_t new_count) { - return reinterpret_cast(this->internal_reallocate_nonzero(TypeInfo::make(), old_ptr, old_count, new_count)); - } - - template - void deallocate(T *ptr, size_t count) { - this->internal_deallocate(TypeInfo::make(), ptr, count); - } - - template - T *create() { - return reinterpret_cast(this->internal_allocate(TypeInfo::make(), 1)); - } - - template - void destroy(T *ptr) { - this->internal_deallocate(TypeInfo::make(), ptr, 1); - } - -protected: - ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate(const TypeInfo &info, size_t count) = 0; - ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate_nonzero(const TypeInfo &info, size_t count) = 0; - virtual void *internal_reallocate(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; - virtual void *internal_reallocate_nonzero(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; - virtual void internal_deallocate(const TypeInfo &info, void *ptr, size_t count) = 0; -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_hash_map.hpp b/src/stage1/mem_hash_map.hpp deleted file mode 100644 index 6abbbf665003..000000000000 --- a/src/stage1/mem_hash_map.hpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_HASH_MAP_HPP -#define ZIG_MEM_HASH_MAP_HPP - -#include "mem.hpp" - -namespace mem { - -template -class HashMap { -public: - void init(Allocator& allocator, int capacity) { - init_capacity(allocator, capacity); - } - void deinit(Allocator& allocator) { - allocator.deallocate(_entries, _capacity); - } - - struct Entry { - K key; - V value; - bool used; - int distance_from_start_index; - }; - - void clear() { - for (int i = 0; i < _capacity; i += 1) { - _entries[i].used = false; - } - _size = 0; - _max_distance_from_start_index = 0; - _modification_count += 1; - } - - int size() const { - return _size; - } - - void put(Allocator& allocator, const K &key, const V &value) { - _modification_count += 1; - internal_put(key, value); - - // if we get too full (60%), double the capacity - if (_size * 5 >= _capacity * 3) { - Entry *old_entries = _entries; - int old_capacity = _capacity; - init_capacity(allocator, _capacity * 2); - // dump all of the old elements into the new table - for (int i = 0; i < old_capacity; i += 1) { - Entry *old_entry = &old_entries[i]; - if (old_entry->used) - internal_put(old_entry->key, old_entry->value); - } - allocator.deallocate(old_entries, old_capacity); - } - } - - Entry *put_unique(Allocator& allocator, const K &key, const V &value) { - // TODO make this more efficient - Entry *entry = internal_get(key); - if (entry) - return entry; - put(allocator, key, value); - return nullptr; - } - - const V &get(const K &key) const { - Entry *entry = internal_get(key); - if (!entry) - zig_panic("key not found"); - return entry->value; - } - - Entry *maybe_get(const K &key) const { - return internal_get(key); - } - - void maybe_remove(const K &key) { - if (maybe_get(key)) { - remove(key); - } - } - - void remove(const K &key) { - _modification_count += 1; - int start_index = key_to_index(key); - for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (!entry->used) - zig_panic("key not found"); - - if (!EqualFn(entry->key, key)) - continue; - - for (; roll_over < _capacity; roll_over += 1) { - int next_index = (start_index + roll_over + 1) % _capacity; - Entry *next_entry = &_entries[next_index]; - if (!next_entry->used || next_entry->distance_from_start_index == 0) { - entry->used = false; - _size -= 1; - return; - } - *entry = *next_entry; - entry->distance_from_start_index -= 1; - entry = next_entry; - } - zig_panic("shifting everything in the table"); - } - zig_panic("key not found"); - } - - class Iterator { - public: - Entry *next() { - if (_inital_modification_count != _table->_modification_count) - zig_panic("concurrent modification"); - if (_count >= _table->size()) - return NULL; - for (; _index < _table->_capacity; _index += 1) { - Entry *entry = &_table->_entries[_index]; - if (entry->used) { - _index += 1; - _count += 1; - return entry; - } - } - zig_panic("no next item"); - } - - private: - const HashMap * _table; - // how many items have we returned - int _count = 0; - // iterator through the entry array - int _index = 0; - // used to detect concurrent modification - uint32_t _inital_modification_count; - Iterator(const HashMap * table) : - _table(table), _inital_modification_count(table->_modification_count) { - } - friend HashMap; - }; - - // you must not modify the underlying HashMap while this iterator is still in use - Iterator entry_iterator() const { - return Iterator(this); - } - -private: - Entry *_entries; - int _capacity; - int _size; - int _max_distance_from_start_index; - // this is used to detect bugs where a hashtable is edited while an iterator is running. - uint32_t _modification_count; - - void init_capacity(Allocator& allocator, int capacity) { - _capacity = capacity; - _entries = allocator.allocate(_capacity); - _size = 0; - _max_distance_from_start_index = 0; - for (int i = 0; i < _capacity; i += 1) { - _entries[i].used = false; - } - } - - void internal_put(K key, V value) { - int start_index = key_to_index(key); - for (int roll_over = 0, distance_from_start_index = 0; - roll_over < _capacity; roll_over += 1, distance_from_start_index += 1) - { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (entry->used && !EqualFn(entry->key, key)) { - if (entry->distance_from_start_index < distance_from_start_index) { - // robin hood to the rescue - Entry tmp = *entry; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - *entry = { - key, - value, - true, - distance_from_start_index, - }; - key = tmp.key; - value = tmp.value; - distance_from_start_index = tmp.distance_from_start_index; - } - continue; - } - - if (!entry->used) { - // adding an entry. otherwise overwriting old value with - // same key - _size += 1; - } - - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - *entry = { - key, - value, - true, - distance_from_start_index, - }; - return; - } - zig_panic("put into a full HashMap"); - } - - - Entry *internal_get(const K &key) const { - int start_index = key_to_index(key); - for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (!entry->used) - return NULL; - - if (EqualFn(entry->key, key)) - return entry; - } - return NULL; - } - - int key_to_index(const K &key) const { - return (int)(HashFunction(key) % ((uint32_t)_capacity)); - } -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_list.hpp b/src/stage1/mem_list.hpp deleted file mode 100644 index df82358ea954..000000000000 --- a/src/stage1/mem_list.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_LIST_HPP -#define ZIG_MEM_LIST_HPP - -#include "mem.hpp" - -namespace mem { - -template -struct List { - void deinit(Allocator *allocator) { - allocator->deallocate(items, capacity); - items = nullptr; - length = 0; - capacity = 0; - } - - void append(Allocator *allocator, const T& item) { - ensure_capacity(allocator, length + 1); - items[length++] = item; - } - - // remember that the pointer to this item is invalid after you - // modify the length of the list - const T & at(size_t index) const { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - - T & at(size_t index) { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - - T pop() { - assert(length >= 1); - return items[--length]; - } - - T *add_one() { - resize(length + 1); - return &last(); - } - - const T & last() const { - assert(length >= 1); - return items[length - 1]; - } - - T & last() { - assert(length >= 1); - return items[length - 1]; - } - - void resize(Allocator *allocator, size_t new_length) { - assert(new_length != SIZE_MAX); - ensure_capacity(allocator, new_length); - length = new_length; - } - - void clear() { - length = 0; - } - - void ensure_capacity(Allocator *allocator, size_t new_capacity) { - if (capacity >= new_capacity) - return; - - size_t better_capacity = capacity; - do { - better_capacity = better_capacity * 5 / 2 + 8; - } while (better_capacity < new_capacity); - - items = allocator->reallocate_nonzero(items, capacity, better_capacity); - capacity = better_capacity; - } - - T swap_remove(size_t index) { - if (length - 1 == index) return pop(); - - assert(index != SIZE_MAX); - assert(index < length); - - T old_item = items[index]; - items[index] = pop(); - return old_item; - } - - T *items{nullptr}; - size_t length{0}; - size_t capacity{0}; -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_type_info.hpp b/src/stage1/mem_type_info.hpp deleted file mode 100644 index ae4b3414ae81..000000000000 --- a/src/stage1/mem_type_info.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_TYPE_INFO_HPP -#define ZIG_MEM_TYPE_INFO_HPP - -namespace mem { - -struct TypeInfo { - size_t size; - size_t alignment; - - template - static constexpr TypeInfo make() { - return {sizeof(T), alignof(T)}; - } -}; - -} // namespace mem - -#endif diff --git a/src/stage1/os.cpp b/src/stage1/os.cpp deleted file mode 100644 index 776d2a291510..000000000000 --- a/src/stage1/os.cpp +++ /dev/null @@ -1,1282 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "os.hpp" -#include "buffer.hpp" -#include "heap.hpp" -#include "util.hpp" -#include "error.hpp" -#include "util_base.hpp" -#include -#include - -#if defined(_WIN32) - -#if !defined(NOMINMAX) -#define NOMINMAX -#endif - -#if !defined(VC_EXTRALEAN) -#define VC_EXTRALEAN -#endif - -#if !defined(WIN32_LEAN_AND_MEAN) -#define WIN32_LEAN_AND_MEAN -#endif - -#if !defined(_WIN32_WINNT) -#define _WIN32_WINNT 0x600 -#endif - -#if !defined(NTDDI_VERSION) -#define NTDDI_VERSION 0x06000000 -#endif - -#include -#include -#include -#include -#include -#include - -// Workaround an upstream LLVM issue. -// See https://github.com/ziglang/zig/issues/7614#issuecomment-752939981 -#if defined(_MSC_VER) && defined(_WIN64) -typedef SSIZE_T ssize_t; -#endif -#else -#define ZIG_OS_POSIX - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) || defined(ZIG_OS_HAIKU) -#include -#endif - -#if defined(ZIG_OS_LINUX) -#include -#endif - -#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) -#include -#endif - -#if defined(__MACH__) -#include -#include -#include -#endif - -#if defined(ZIG_OS_WINDOWS) -static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le); -static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice utf8); -static uint64_t windows_perf_freq; -#elif defined(__MACH__) -static clock_serv_t macos_calendar_clock; -static clock_serv_t macos_monotonic_clock; -#endif - -#include -#include -#include - -#if !defined(environ) -extern char **environ; -#endif - -void os_path_dirname(Buf *full_path, Buf *out_dirname) { - return os_path_split(full_path, out_dirname, nullptr); -} - -bool os_is_sep(uint8_t c) { -#if defined(ZIG_OS_WINDOWS) - return c == '\\' || c == '/'; -#else - return c == '/'; -#endif -} - -void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { - size_t len = buf_len(full_path); - if (len != 0) { - size_t last_index = len - 1; - char last_char = buf_ptr(full_path)[last_index]; - if (os_is_sep(last_char)) { - if (last_index == 0) { - if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1); - if (out_basename) buf_init_from_str(out_basename, ""); - return; - } - last_index -= 1; - } - for (size_t i = last_index;;) { - uint8_t c = buf_ptr(full_path)[i]; - if (os_is_sep(c)) { - if (out_dirname) { - buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i); - } - if (out_basename) { - buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1)); - } - return; - } - if (i == 0) break; - i -= 1; - } - } - if (out_dirname) buf_init_from_mem(out_dirname, ".", 1); - if (out_basename) buf_init_from_buf(out_basename, full_path); -} - -void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) { - if (buf_len(full_path) == 0) { - if (out_basename) buf_init_from_str(out_basename, ""); - if (out_extname) buf_init_from_str(out_extname, ""); - return; - } - size_t i = buf_len(full_path) - 1; - while (true) { - if (buf_ptr(full_path)[i] == '.') { - if (out_basename) { - buf_resize(out_basename, 0); - buf_append_mem(out_basename, buf_ptr(full_path), i); - } - - if (out_extname) { - buf_resize(out_extname, 0); - buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i); - } - return; - } - - if (i == 0) { - if (out_basename) buf_init_from_buf(out_basename, full_path); - if (out_extname) buf_init_from_str(out_extname, ""); - return; - } - i -= 1; - } -} - -void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { - if (buf_len(dirname) == 0) { - buf_init_from_buf(out_full_path, basename); - return; - } - - buf_init_from_buf(out_full_path, dirname); - uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1); - if (!os_is_sep(c)) - buf_append_char(out_full_path, ZIG_OS_SEP_CHAR); - buf_append_buf(out_full_path, basename); -} - - -#if defined(ZIG_OS_WINDOWS) -// Ported from std/os/path.zig -static bool isAbsoluteWindows(Slice path) { - if (path.ptr[0] == '/') - return true; - - if (path.ptr[0] == '\\') { - return true; - } - if (path.len < 3) { - return false; - } - if (path.ptr[1] == ':') { - if (path.ptr[2] == '/') - return true; - if (path.ptr[2] == '\\') - return true; - } - return false; -} - -enum WindowsPathKind { - WindowsPathKindNone, - WindowsPathKindDrive, - WindowsPathKindNetworkShare, -}; - -struct WindowsPath { - Slice disk_designator; - WindowsPathKind kind; - bool is_abs; -}; - - -// Ported from std/os/path.zig -static WindowsPath windowsParsePath(Slice path) { - if (path.len >= 2 && path.ptr[1] == ':') { - return WindowsPath{ - path.slice(0, 2), - WindowsPathKindDrive, - isAbsoluteWindows(path), - }; - } - if (path.len >= 1 && (path.ptr[0] == '/' || path.ptr[0] == '\\') && - (path.len == 1 || (path.ptr[1] != '/' && path.ptr[1] != '\\'))) - { - return WindowsPath{ - path.slice(0, 0), - WindowsPathKindNone, - true, - }; - } - WindowsPath relative_path = { - str(""), - WindowsPathKindNone, - false, - }; - if (path.len < strlen("//a/b")) { - return relative_path; - } - - { - if (memStartsWith(path, str("//"))) { - if (path.ptr[2] == '/') { - return relative_path; - } - - SplitIterator it = memSplit(path, str("/")); - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - return WindowsPath{ - path.slice(0, it.index), - WindowsPathKindNetworkShare, - isAbsoluteWindows(path), - }; - } - } - { - if (memStartsWith(path, str("\\\\"))) { - if (path.ptr[2] == '\\') { - return relative_path; - } - - SplitIterator it = memSplit(path, str("\\")); - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - return WindowsPath{ - path.slice(0, it.index), - WindowsPathKindNetworkShare, - isAbsoluteWindows(path), - }; - } - } - return relative_path; -} - -// Ported from std/os/path.zig -static uint8_t asciiUpper(uint8_t byte) { - if (byte >= 'a' && byte <= 'z') { - return 'A' + (byte - 'a'); - } - return byte; -} - -// Ported from std/os/path.zig -static bool asciiEqlIgnoreCase(Slice s1, Slice s2) { - if (s1.len != s2.len) - return false; - for (size_t i = 0; i < s1.len; i += 1) { - if (asciiUpper(s1.ptr[i]) != asciiUpper(s2.ptr[i])) - return false; - } - return true; -} - -// Ported from std/os/path.zig -static bool compareDiskDesignators(WindowsPathKind kind, Slice p1, Slice p2) { - switch (kind) { - case WindowsPathKindNone: - assert(p1.len == 0); - assert(p2.len == 0); - return true; - case WindowsPathKindDrive: - return asciiUpper(p1.ptr[0]) == asciiUpper(p2.ptr[0]); - case WindowsPathKindNetworkShare: - uint8_t sep1 = p1.ptr[0]; - uint8_t sep2 = p2.ptr[0]; - - SplitIterator it1 = memSplit(p1, {&sep1, 1}); - SplitIterator it2 = memSplit(p2, {&sep2, 1}); - - // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value) && - asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value); - } - zig_unreachable(); -} - -// Ported from std/os/path.zig -static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) { - if (paths_len == 0) { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - return cwd; - } - - // determine which disk designator we will result with, if any - char result_drive_buf[3] = {'_', ':', '\0'}; // 0 needed for strlen later - Slice result_disk_designator = str(""); - WindowsPathKind have_drive_kind = WindowsPathKindNone; - bool have_abs_path = false; - size_t first_index = 0; - size_t max_size = 0; - for (size_t i = 0; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - if (parsed.is_abs) { - have_abs_path = true; - first_index = i; - max_size = result_disk_designator.len; - } - switch (parsed.kind) { - case WindowsPathKindDrive: - result_drive_buf[0] = asciiUpper(parsed.disk_designator.ptr[0]); - result_disk_designator = str(result_drive_buf); - have_drive_kind = WindowsPathKindDrive; - break; - case WindowsPathKindNetworkShare: - result_disk_designator = parsed.disk_designator; - have_drive_kind = WindowsPathKindNetworkShare; - break; - case WindowsPathKindNone: - break; - } - max_size += p.len + 1; - } - - // if we will result with a disk designator, loop again to determine - // which is the last time the disk designator is absolutely specified, if any - // and count up the max bytes for paths related to this disk designator - if (have_drive_kind != WindowsPathKindNone) { - have_abs_path = false; - first_index = 0; - max_size = result_disk_designator.len; - bool correct_disk_designator = false; - - for (size_t i = 0; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - if (parsed.kind != WindowsPathKindNone) { - if (parsed.kind == have_drive_kind) { - correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); - } else { - continue; - } - } - if (!correct_disk_designator) { - continue; - } - if (parsed.is_abs) { - first_index = i; - max_size = result_disk_designator.len; - have_abs_path = true; - } - max_size += p.len + 1; - } - } - - // Allocate result and fill in the disk designator, calling getCwd if we have to. - Slice result; - size_t result_index = 0; - - if (have_abs_path) { - switch (have_drive_kind) { - case WindowsPathKindDrive: { - result = Slice::alloc(max_size); - - memCopy(result, result_disk_designator); - result_index += result_disk_designator.len; - break; - } - case WindowsPathKindNetworkShare: { - result = Slice::alloc(max_size); - SplitIterator it = memSplit(buf_to_slice(paths_ptr[first_index]), str("/\\")); - Slice server_name = SplitIterator_next(&it).value; - Slice other_name = SplitIterator_next(&it).value; - - result.ptr[result_index] = '\\'; - result_index += 1; - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), server_name); - result_index += server_name.len; - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), other_name); - result_index += other_name.len; - - result_disk_designator = result.slice(0, result_index); - break; - } - case WindowsPathKindNone: { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - WindowsPath parsed_cwd = windowsParsePath(buf_to_slice(&cwd)); - result = Slice::alloc(max_size + parsed_cwd.disk_designator.len + 1); - memCopy(result, parsed_cwd.disk_designator); - result_index += parsed_cwd.disk_designator.len; - result_disk_designator = result.slice(0, parsed_cwd.disk_designator.len); - if (parsed_cwd.kind == WindowsPathKindDrive) { - result.ptr[0] = asciiUpper(result.ptr[0]); - } - have_drive_kind = parsed_cwd.kind; - break; - } - } - } else { - // TODO call get cwd for the result_disk_designator instead of the global one - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - result = Slice::alloc(max_size + buf_len(&cwd) + 1); - - memCopy(result, buf_to_slice(&cwd)); - result_index += buf_len(&cwd); - WindowsPath parsed_cwd = windowsParsePath(result.slice(0, result_index)); - result_disk_designator = parsed_cwd.disk_designator; - if (parsed_cwd.kind == WindowsPathKindDrive) { - result.ptr[0] = asciiUpper(result.ptr[0]); - // Remove the trailing slash if present, eg. if the cwd is a root - // directory. - if (buf_ends_with_mem(&cwd, "\\", 1)) { - result_index -= 1; - } - } - have_drive_kind = parsed_cwd.kind; - } - - // Now we know the disk designator to use, if any, and what kind it is. And our result - // is big enough to append all the paths to. - bool correct_disk_designator = true; - for (size_t i = first_index; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - - if (parsed.kind != WindowsPathKindNone) { - if (parsed.kind == have_drive_kind) { - correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); - } else { - continue; - } - } - if (!correct_disk_designator) { - continue; - } - SplitIterator it = memSplit(p.sliceFrom(parsed.disk_designator.len), str("/\\")); - while (true) { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) break; - Slice component = opt_component.value; - if (memEql(component, str("."))) { - continue; - } else if (memEql(component, str(".."))) { - while (true) { - if (result_index == 0 || result_index == result_disk_designator.len) - break; - result_index -= 1; - if (result.ptr[result_index] == '\\' || result.ptr[result_index] == '/') - break; - } - } else { - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), component); - result_index += component.len; - } - } - } - - if (result_index == result_disk_designator.len) { - result.ptr[result_index] = '\\'; - result_index += 1; - } - - Buf return_value = BUF_INIT; - buf_init_from_mem(&return_value, (char *)result.ptr, result_index); - return return_value; -} -#endif - -#if defined(ZIG_OS_POSIX) -// Ported from std/os/path.zig -static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) { - if (paths_len == 0) { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - return cwd; - } - - size_t first_index = 0; - bool have_abs = false; - size_t max_size = 0; - for (size_t i = 0; i < paths_len; i += 1) { - Buf *p = paths_ptr[i]; - if (buf_ptr(p)[0] == '/') { - first_index = i; - have_abs = true; - max_size = 0; - } - max_size += buf_len(p) + 1; - } - - uint8_t *result_ptr; - size_t result_len; - size_t result_index = 0; - - if (have_abs) { - result_len = max_size; - result_ptr = heap::c_allocator.allocate_nonzero(result_len); - } else { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - result_len = max_size + buf_len(&cwd) + 1; - result_ptr = heap::c_allocator.allocate_nonzero(result_len); - memcpy(result_ptr, buf_ptr(&cwd), buf_len(&cwd)); - result_index += buf_len(&cwd); - } - - for (size_t i = first_index; i < paths_len; i += 1) { - Buf *p = paths_ptr[i]; - SplitIterator it = memSplit(buf_to_slice(p), str("/")); - while (true) { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) break; - Slice component = opt_component.value; - - if (memEql(component, str("."))) { - continue; - } else if (memEql(component, str(".."))) { - while (true) { - if (result_index == 0) - break; - result_index -= 1; - if (result_ptr[result_index] == '/') - break; - } - } else { - result_ptr[result_index] = '/'; - result_index += 1; - memcpy(result_ptr + result_index, component.ptr, component.len); - result_index += component.len; - } - } - } - - if (result_index == 0) { - result_ptr[0] = '/'; - result_index += 1; - } - - Buf return_value = BUF_INIT; - buf_init_from_mem(&return_value, (char *)result_ptr, result_index); - heap::c_allocator.deallocate(result_ptr, result_len); - return return_value; -} -#endif - -// Ported from std/os/path.zig -Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { -#if defined(ZIG_OS_WINDOWS) - return os_path_resolve_windows(paths_ptr, paths_len); -#elif defined(ZIG_OS_POSIX) - return os_path_resolve_posix(paths_ptr, paths_len); -#else -#error "missing os_path_resolve implementation" -#endif -} - -Error os_fetch_file(FILE *f, Buf *out_buf) { - static const ssize_t buf_size = 0x2000; - buf_resize(out_buf, buf_size); - ssize_t actual_buf_len = 0; - - for (;;) { - size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); - actual_buf_len += amt_read; - - if (amt_read != buf_size) { - if (feof(f)) { - buf_resize(out_buf, actual_buf_len); - return ErrorNone; - } else { - return ErrorFileSystem; - } - } - - buf_resize(out_buf, actual_buf_len + buf_size); - } - zig_unreachable(); -} - -Error os_write_file(Buf *full_path, Buf *contents) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); - FILE *f = _wfopen(&path_space.data.items[0], L"wb"); -#else - FILE *f = fopen(buf_ptr(full_path), "wb"); -#endif - if (!f) { - zig_panic("os_write_file failed for %s", buf_ptr(full_path)); - } - size_t amt_written = fwrite(buf_ptr(contents), 1, buf_len(contents), f); - if (amt_written != (size_t)buf_len(contents)) - zig_panic("write failed: %s", strerror(errno)); - if (fclose(f)) - zig_panic("close failed"); - return ErrorNone; -} - -static Error copy_open_files(FILE *src_f, FILE *dest_f) { - static const size_t buf_size = 2048; - char buf[buf_size]; - for (;;) { - size_t amt_read = fread(buf, 1, buf_size, src_f); - if (amt_read != buf_size) { - if (ferror(src_f)) { - return ErrorFileSystem; - } - } - size_t amt_written = fwrite(buf, 1, amt_read, dest_f); - if (amt_written != amt_read) { - return ErrorFileSystem; - } - if (feof(src_f)) { - return ErrorNone; - } - } -} - -Error os_copy_file(Buf *src_path, Buf *dest_path) { -#if defined(ZIG_OS_WINDOWS) - PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); - FILE *src_f = _wfopen(&src_path_space.data.items[0], L"rb"); -#else - FILE *src_f = fopen(buf_ptr(src_path), "rb"); -#endif - if (!src_f) { - int err = errno; - if (err == ENOENT) { - return ErrorFileNotFound; - } else if (err == EACCES || err == EPERM) { - return ErrorAccess; - } else { - return ErrorFileSystem; - } - } -#if defined(ZIG_OS_WINDOWS) - PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); - FILE *dest_f = _wfopen(&dest_path_space.data.items[0], L"wb"); -#else - FILE *dest_f = fopen(buf_ptr(dest_path), "wb"); -#endif - if (!dest_f) { - int err = errno; - if (err == ENOENT) { - fclose(src_f); - return ErrorFileNotFound; - } else if (err == EACCES || err == EPERM) { - fclose(src_f); - return ErrorAccess; - } else { - fclose(src_f); - return ErrorFileSystem; - } - } - Error err = copy_open_files(src_f, dest_f); - fclose(src_f); - fclose(dest_f); - return err; -} - -Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); - FILE *f = _wfopen(&path_space.data.items[0], L"rb"); -#else - FILE *f = fopen(buf_ptr(full_path), "rb"); -#endif - if (!f) { - switch (errno) { - case EACCES: - return ErrorAccess; - case EINTR: - return ErrorInterrupted; - case EINVAL: - return ErrorInvalidFilename; - case ENFILE: - case ENOMEM: - return ErrorSystemResources; - case ENOENT: - return ErrorFileNotFound; - default: - return ErrorFileSystem; - } - } - Error result = os_fetch_file(f, out_contents); - fclose(f); - return result; -} - -Error os_get_cwd(Buf *out_cwd) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space; - if (GetCurrentDirectoryW(PATH_MAX_WIDE, &path_space.data.items[0]) == 0) { - zig_panic("GetCurrentDirectory failed"); - } - utf16le_ptr_to_utf8(out_cwd, &path_space.data.items[0]); - return ErrorNone; -#elif defined(ZIG_OS_POSIX) - char buf[PATH_MAX]; - char *res = getcwd(buf, PATH_MAX); - if (res == nullptr) { - zig_panic("unable to get cwd: %s", strerror(errno)); - } - buf_init_from_str(out_cwd, res); - return ErrorNone; -#else -#error "missing os_get_cwd implementation" -#endif -} - -#if defined(ZIG_OS_WINDOWS) -#define is_wprefix(s, prefix) \ - (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) -static bool is_stderr_cyg_pty(void) { - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - if (stderr_handle == INVALID_HANDLE_VALUE) - return false; - - const int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; - FILE_NAME_INFO *nameinfo; - WCHAR *p = NULL; - - // Cygwin/msys's pty is a pipe. - if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { - return 0; - } - nameinfo = reinterpret_cast(heap::c_allocator.allocate(size)); - if (nameinfo == NULL) { - return 0; - } - // Check the name of the pipe: - // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' - if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { - nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; - p = nameinfo->FileName; - if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ - p += 8; - } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */ - p += 6; - } else { - p = NULL; - } - if (p != NULL) { - while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */ - ++p; - if (is_wprefix(p, L"-pty")) { - p += 4; - } else { - p = NULL; - } - } - if (p != NULL) { - while (*p && isdigit(*p)) /* Skip pty number. */ - ++p; - if (is_wprefix(p, L"-from-master")) { - //p += 12; - } else if (is_wprefix(p, L"-to-master")) { - //p += 10; - } else { - p = NULL; - } - } - } - heap::c_allocator.deallocate(reinterpret_cast(nameinfo), size); - return (p != NULL); -} -#endif - -bool os_stderr_supports_color(void) { - if (getenv("NO_COLOR") != NULL) return false; -#if defined(ZIG_OS_WINDOWS) - return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); -#elif defined(ZIG_OS_POSIX) - return isatty(STDERR_FILENO) != 0; -#else -#error "missing os_stderr_supports_color implementation" -#endif -} - -Error os_rename(Buf *src_path, Buf *dest_path) { - if (buf_eql_buf(src_path, dest_path)) { - return ErrorNone; - } -#if defined(ZIG_OS_WINDOWS) - PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); - PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); - if (!MoveFileExW(&src_path_space.data.items[0], &dest_path_space.data.items[0], MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { - return ErrorFileSystem; - } -#else - if (rename(buf_ptr(src_path), buf_ptr(dest_path)) == -1) { - return ErrorFileSystem; - } -#endif - return ErrorNone; -} - -OsTimeStamp os_timestamp_monotonic(void) { - OsTimeStamp result; -#if defined(ZIG_OS_WINDOWS) - uint64_t counts; - QueryPerformanceCounter((LARGE_INTEGER*)&counts); - result.sec = counts / windows_perf_freq; - result.nsec = (counts % windows_perf_freq) * 1000000000u / windows_perf_freq; -#elif defined(__MACH__) - mach_timespec_t mts; - - kern_return_t err = clock_get_time(macos_monotonic_clock, &mts); - assert(!err); - - result.sec = mts.tv_sec; - result.nsec = mts.tv_nsec; -#else - struct timespec tms; - clock_gettime(CLOCK_MONOTONIC, &tms); - - result.sec = tms.tv_sec; - result.nsec = tms.tv_nsec; -#endif - return result; -} - -Error os_make_path(Buf *path) { - Buf resolved_path = os_path_resolve(&path, 1); - - size_t end_index = buf_len(&resolved_path); - Error err; - while (true) { - if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) { - if (err == ErrorPathAlreadyExists) { - if (end_index == buf_len(&resolved_path)) - return ErrorNone; - } else if (err == ErrorFileNotFound) { - // march end_index backward until next path component - while (true) { - end_index -= 1; - if (os_is_sep(buf_ptr(&resolved_path)[end_index])) - break; - } - continue; - } else { - return err; - } - } - if (end_index == buf_len(&resolved_path)) - return ErrorNone; - // march end_index forward until next path component - while (true) { - end_index += 1; - if (end_index == buf_len(&resolved_path) || os_is_sep(buf_ptr(&resolved_path)[end_index])) - break; - } - } - return ErrorNone; -} - -Error os_make_dir(Buf *path) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(path)); - - if (!CreateDirectoryW(&path_space.data.items[0], NULL)) { - if (GetLastError() == ERROR_ALREADY_EXISTS) - return ErrorPathAlreadyExists; - if (GetLastError() == ERROR_PATH_NOT_FOUND) - return ErrorFileNotFound; - if (GetLastError() == ERROR_ACCESS_DENIED) - return ErrorAccess; - return ErrorUnexpected; - } - return ErrorNone; -#else - if (mkdir(buf_ptr(path), 0755) == -1) { - if (errno == EEXIST) - return ErrorPathAlreadyExists; - if (errno == ENOENT) - return ErrorFileNotFound; - if (errno == EACCES) - return ErrorAccess; - return ErrorUnexpected; - } - return ErrorNone; -#endif -} - - -int os_init(void) { -#if defined(ZIG_OS_WINDOWS) - _setmode(fileno(stdout), _O_BINARY); - _setmode(fileno(stderr), _O_BINARY); - if (!QueryPerformanceFrequency((LARGE_INTEGER*)&windows_perf_freq)) { - return ErrorSystemResources; - } -#elif defined(__MACH__) - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &macos_monotonic_clock); - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &macos_calendar_clock); -#endif - return 0; -} - -#define VT_RED "\x1b[31;1m" -#define VT_GREEN "\x1b[32;1m" -#define VT_CYAN "\x1b[36;1m" -#define VT_WHITE "\x1b[37;1m" -#define VT_BOLD "\x1b[0;1m" -#define VT_RESET "\x1b[0m" - -static void set_color_posix(TermColor color) { - switch (color) { - case TermColorRed: - fprintf(stderr, VT_RED); - break; - case TermColorGreen: - fprintf(stderr, VT_GREEN); - break; - case TermColorCyan: - fprintf(stderr, VT_CYAN); - break; - case TermColorWhite: - fprintf(stderr, VT_WHITE); - break; - case TermColorBold: - fprintf(stderr, VT_BOLD); - break; - case TermColorReset: - fprintf(stderr, VT_RESET); - break; - } -} - - -#if defined(ZIG_OS_WINDOWS) -bool got_orig_console_attrs = false; -WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; -#endif - -void os_stderr_set_color(TermColor color) { -#if defined(ZIG_OS_WINDOWS) - if (is_stderr_cyg_pty()) { - set_color_posix(color); - return; - } - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - if (stderr_handle == INVALID_HANDLE_VALUE) - zig_panic("unable to get stderr handle"); - fflush(stderr); - - if (!got_orig_console_attrs) { - got_orig_console_attrs = true; - CONSOLE_SCREEN_BUFFER_INFO info; - if (GetConsoleScreenBufferInfo(stderr_handle, &info)) { - original_console_attributes = info.wAttributes; - } - } - - switch (color) { - case TermColorRed: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_RED|FOREGROUND_INTENSITY); - break; - case TermColorGreen: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_INTENSITY); - break; - case TermColorCyan: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); - break; - case TermColorWhite: - case TermColorBold: - SetConsoleTextAttribute(stderr_handle, - FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); - break; - case TermColorReset: - SetConsoleTextAttribute(stderr_handle, original_console_attributes); - break; - } -#else - set_color_posix(color); -#endif -} - -#if defined(ZIG_OS_WINDOWS) -// Ported from std/unicode.zig -struct Utf16LeIterator { - uint8_t *bytes; - size_t i; -}; - -// Ported from std/unicode.zig -static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) { - return {(uint8_t*)ptr, 0}; -} - -// Ported from std/unicode.zig -static Optional Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) { - if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0) - return {}; - uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - if ((c0 & ~((uint32_t)0x03ff)) == 0xd800) { - // surrogate pair - it->i += 2; - assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0); - uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - assert((c1 & ~((uint32_t)0x03ff)) == 0xdc00); - it->i += 2; - return Optional::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff))); - } else { - assert((c0 & ~((uint32_t)0x03ff)) != 0xdc00); - it->i += 2; - return Optional::some(c0); - } -} - -// Ported from std/unicode.zig -static uint8_t utf8CodepointSequenceLength(uint32_t c) { - if (c < 0x80) return 1; - if (c < 0x800) return 2; - if (c < 0x10000) return 3; - if (c < 0x110000) return 4; - zig_unreachable(); -} - -// Ported from std.unicode.utf8ByteSequenceLength -static uint8_t utf8ByteSequenceLength(uint8_t first_byte) { - if (first_byte < 0b10000000) return 1; - if ((first_byte & 0b11100000) == 0b11000000) return 2; - if ((first_byte & 0b11110000) == 0b11100000) return 3; - if ((first_byte & 0b11111000) == 0b11110000) return 4; - zig_unreachable(); -} - -// Ported from std/unicode.zig -static size_t utf8Encode(uint32_t c, Slice out) { - size_t length = utf8CodepointSequenceLength(c); - assert(out.len >= length); - switch (length) { - // The pattern for each is the same - // - Increasing the initial shift by 6 each time - // - Each time after the first shorten the shifted - // value to a max of 0b111111 (63) - case 1: - out.ptr[0] = c; // Can just do 0 + codepoint for initial range - break; - case 2: - out.ptr[0] = 0b11000000 | (c >> 6); - out.ptr[1] = 0b10000000 | (c & 0b111111); - break; - case 3: - assert(!(0xd800 <= c && c <= 0xdfff)); - out.ptr[0] = 0b11100000 | (c >> 12); - out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111); - out.ptr[2] = 0b10000000 | (c & 0b111111); - break; - case 4: - out.ptr[0] = 0b11110000 | (c >> 18); - out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111); - out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111); - out.ptr[3] = 0b10000000 | (c & 0b111111); - break; - default: - zig_unreachable(); - } - return length; -} - -// Ported from std.unicode.utf8Decode2 -static uint32_t utf8Decode2(Slice bytes) { - assert(bytes.len == 2); - assert((bytes.at(0) & 0b11100000) == 0b11000000); - - uint32_t value = bytes.at(0) & 0b00011111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert(value >= 0x80); - return value; -} - -// Ported from std.unicode.utf8Decode3 -static uint32_t utf8Decode3(Slice bytes) { - assert(bytes.len == 3); - assert((bytes.at(0) & 0b11110000) == 0b11100000); - - uint32_t value = bytes.at(0) & 0b00001111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert((bytes.at(2) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(2) & 0b00111111; - - assert(value >= 0x80); - assert(value < 0xd800 || value > 0xdfff); - return value; -} - -// Ported from std.unicode.utf8Decode4 -static uint32_t utf8Decode4(Slice bytes) { - assert(bytes.len == 4); - assert((bytes.at(0) & 0b11111000) == 0b11110000); - - uint32_t value = bytes.at(0) & 0b00000111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert((bytes.at(2) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(2) & 0b00111111; - - assert((bytes.at(3) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(3) & 0b00111111; - - assert(value >= 0x10000 && value <= 0x10FFFF); - return value; -} - -// Ported from std.unicode.utf8Decode -static uint32_t utf8Decode(Slice bytes) { - switch (bytes.len) { - case 1: - return bytes.at(0); - break; - case 2: - return utf8Decode2(bytes); - break; - case 3: - return utf8Decode3(bytes); - break; - case 4: - return utf8Decode4(bytes); - break; - default: - zig_unreachable(); - } -} -// Ported from std.unicode.utf16leToUtf8Alloc -static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { - // optimistically guess that it will all be ascii. - buf_resize(out, 0); - size_t out_index = 0; - Utf16LeIterator it = Utf16LeIterator_init(utf16le); - for (;;) { - Optional opt_codepoint = Utf16LeIterator_nextCodepoint(&it); - if (!opt_codepoint.is_some) break; - uint32_t codepoint = opt_codepoint.value; - - size_t utf8_len = utf8CodepointSequenceLength(codepoint); - buf_resize(out, buf_len(out) + utf8_len); - utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index}); - out_index += utf8_len; - } -} - -// Ported from std.unicode.utf8ToUtf16Le -static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice utf8) { - size_t dest_i = 0; - size_t src_i = 0; - while (src_i < utf8.len) { - uint8_t n = utf8ByteSequenceLength(utf8.at(src_i)); - size_t next_src_i = src_i + n; - uint32_t codepoint = utf8Decode(utf8.slice(src_i, next_src_i)); - if (codepoint < 0x10000) { - utf16_le[dest_i] = codepoint; - dest_i += 1; - } else { - WCHAR high = ((codepoint - 0x10000) >> 10) + 0xD800; - WCHAR low = (codepoint & 0x3FF) + 0xDC00; - utf16_le[dest_i] = high; - utf16_le[dest_i + 1] = low; - dest_i += 2; - } - src_i = next_src_i; - } - return dest_i; -} - -// Ported from std.os.windows.sliceToPrefixedFileW -PathSpace slice_to_prefixed_file_w(Slice path) { - PathSpace path_space; - for (size_t idx = 0; idx < path.len; idx++) { - assert(path.ptr[idx] != '*' && path.ptr[idx] != '?' && path.ptr[idx] != '"' && - path.ptr[idx] != '<' && path.ptr[idx] != '>' && path.ptr[idx] != '|'); - } - - size_t start_index; - if (memStartsWith(path, str("\\?")) || !isAbsoluteWindows(path)) { - start_index = 0; - } else { - static WCHAR prefix[4] = { u'\\', u'?', u'?', u'\\' }; - memCopy(path_space.data.slice(), Slice { prefix, 4 }); - start_index = 4; - } - - path_space.len = start_index + utf8_to_utf16le(path_space.data.slice().sliceFrom(start_index).ptr, path); - assert(path_space.len <= path_space.data.len); - - Slice path_slice = path_space.data.slice().slice(0, path_space.len); - for (size_t elem_idx = 0; elem_idx < path_slice.len; elem_idx += 1) { - if (path_slice.at(elem_idx) == '/') { - path_slice.at(elem_idx) = '\\'; - } - } - - path_space.data.items[path_space.len] = 0; - return path_space; -} -#endif diff --git a/src/stage1/os.hpp b/src/stage1/os.hpp deleted file mode 100644 index 6d086c890167..000000000000 --- a/src/stage1/os.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_OS_HPP -#define ZIG_OS_HPP - -#include "list.hpp" -#include "buffer.hpp" -#include "error.hpp" -#include "zig_llvm.h" -#include "windows_sdk.h" - -#include -#include - -#if defined(__APPLE__) -#define ZIG_OS_DARWIN -#elif defined(_WIN32) -#define ZIG_OS_WINDOWS -#elif defined(__linux__) -#define ZIG_OS_LINUX -#elif defined(__FreeBSD__) -#define ZIG_OS_FREEBSD -#elif defined(__NetBSD__) -#define ZIG_OS_NETBSD -#elif defined(__DragonFly__) -#define ZIG_OS_DRAGONFLY -#elif defined(__OpenBSD__) -#define ZIG_OS_OPENBSD -#elif defined(__HAIKU__) -#define ZIG_OS_HAIKU -#elif defined(__sun) -#define ZIG_OS_SOLARIS -#else -#define ZIG_OS_UNKNOWN -#endif - -#if defined(__x86_64__) -#define ZIG_ARCH_X86_64 -#elif defined(__aarch64__) -#define ZIG_ARCH_ARM64 -#elif defined(__ARM_EABI__) -#define ZIG_ARCH_ARM -#else -#define ZIG_ARCH_UNKNOWN -#endif - -#if defined(ZIG_OS_WINDOWS) -#define ZIG_PRI_usize "Iu" -#define ZIG_PRI_i64 "I64d" -#define ZIG_PRI_u64 "I64u" -#define ZIG_PRI_llu "I64u" -#define ZIG_PRI_x64 "I64x" -#define OS_SEP "\\" -#define ZIG_OS_SEP_CHAR '\\' -#else -#define ZIG_PRI_usize "zu" -#define ZIG_PRI_i64 PRId64 -#define ZIG_PRI_u64 PRIu64 -#define ZIG_PRI_llu "llu" -#define ZIG_PRI_x64 PRIx64 -#define OS_SEP "/" -#define ZIG_OS_SEP_CHAR '/' -#endif - -enum TermColor { - TermColorRed, - TermColorGreen, - TermColorCyan, - TermColorWhite, - TermColorBold, - TermColorReset, -}; - -struct OsTimeStamp { - int64_t sec; - int64_t nsec; -}; - -int os_init(void); - -void os_path_dirname(Buf *full_path, Buf *out_dirname); -void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); -void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname); -void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); -Buf os_path_resolve(Buf **paths_ptr, size_t paths_len); -bool os_path_is_absolute(Buf *path); - -Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); -Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); - -Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); -Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); - -Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); -Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); - -Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); - -bool os_stderr_supports_color(void); -void os_stderr_set_color(TermColor color); - -Error os_rename(Buf *src_path, Buf *dest_path); -OsTimeStamp os_timestamp_monotonic(void); - -bool os_is_sep(uint8_t c); - -const size_t PATH_MAX_WIDE = 32767; - -struct PathSpace { - Array data; - size_t len; -}; - -PathSpace slice_to_prefixed_file_w(Slice path); -#endif diff --git a/src/stage1/parse_f128.c b/src/stage1/parse_f128.c deleted file mode 100644 index 493375e4d1db..000000000000 --- a/src/stage1/parse_f128.c +++ /dev/null @@ -1,1085 +0,0 @@ -// Code ported from musl libc 8f12c4e110acb3bbbdc8abfb3a552c3ced718039 -// and then modified to use softfloat and to assume f128 for everything - -#include "parse_f128.h" -#include "softfloat.h" -#include "zigendian.h" -#include -#include -#include -#include -#include -#include - -#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) -#define shlim(f, lim) __shlim((f), (lim)) -#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f)) -#define shunget(f) ((f)->shlim>=0 ? (void)(f)->rpos-- : (void)0) - -#define sh_fromstring(f, s) \ - ((f)->buf = (f)->rpos = (void *)(s), (f)->rend = (void*)-1) - -#define LD_B1B_DIG 4 -#define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191 -#define KMAX 2048 - -#define MASK (KMAX-1) - -#define CONCAT2(x,y) x ## y -#define CONCAT(x,y) CONCAT2(x,y) - -#define F_PERM 1 -#define F_NORD 4 -#define F_NOWR 8 -#define F_EOF 16 -#define F_ERR 32 -#define F_SVB 64 -#define F_APP 128 - -#define EOF (-1) - -#define LDBL_MANT_DIG 113 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_EXP 16384 - -#define LDBL_DIG 33 -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_10_EXP 4932 - -#define DECIMAL_DIG 36 - -#if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN -union ldshape { - float128_t f; - struct { - uint64_t lo; - uint32_t mid; - uint16_t top; - uint16_t se; - } i; - struct { - uint64_t lo; - uint64_t hi; - } i2; -}; -#elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN -union ldshape { - float128_t f; - struct { - uint16_t se; - uint16_t top; - uint32_t mid; - uint64_t lo; - } i; - struct { - uint64_t hi; - uint64_t lo; - } i2; -}; -#else -#error Unsupported endian -#endif - -struct MuslFILE { - unsigned flags; - unsigned char *rpos, *rend; - int (*close)(struct MuslFILE *); - unsigned char *wend, *wpos; - unsigned char *mustbezero_1; - unsigned char *wbase; - size_t (*read)(struct MuslFILE *, unsigned char *, size_t); - size_t (*write)(struct MuslFILE *, const unsigned char *, size_t); - off_t (*seek)(struct MuslFILE *, off_t, int); - unsigned char *buf; - size_t buf_size; - struct MuslFILE *prev, *next; - int fd; - int pipe_pid; - long lockcount; - int mode; - volatile int lock; - int lbf; - void *cookie; - off_t off; - char *getln_buf; - void *mustbezero_2; - unsigned char *shend; - off_t shlim, shcnt; - struct MuslFILE *prev_locked, *next_locked; - struct __locale_struct *locale; -}; - -static void __shlim(struct MuslFILE *f, off_t lim) -{ - f->shlim = lim; - f->shcnt = f->buf - f->rpos; - /* If lim is nonzero, rend must be a valid pointer. */ - if (lim && f->rend - f->rpos > lim) - f->shend = f->rpos + lim; - else - f->shend = f->rend; -} - -static int __toread(struct MuslFILE *f) -{ - f->mode |= f->mode-1; - if (f->wpos != f->wbase) f->write(f, 0, 0); - f->wpos = f->wbase = f->wend = 0; - if (f->flags & F_NORD) { - f->flags |= F_ERR; - return EOF; - } - f->rpos = f->rend = f->buf + f->buf_size; - return (f->flags & F_EOF) ? EOF : 0; -} - -static int __uflow(struct MuslFILE *f) -{ - unsigned char c; - if (!__toread(f) && f->read(f, &c, 1)==1) return c; - return EOF; -} - -static int __shgetc(struct MuslFILE *f) -{ - int c; - off_t cnt = shcnt(f); - if ((f->shlim && cnt >= f->shlim) || (c=__uflow(f)) < 0) { - f->shcnt = f->buf - f->rpos + cnt; - f->shend = f->rpos; - f->shlim = -1; - return EOF; - } - cnt++; - if (f->shlim && f->rend - f->rpos > f->shlim - cnt) - f->shend = f->rpos + (f->shlim - cnt); - else - f->shend = f->rend; - f->shcnt = f->buf - f->rpos + cnt; - if (f->rpos[-1] != c) f->rpos[-1] = c; - return c; -} - -static long long scanexp(struct MuslFILE *f, int pok) -{ - int c; - int x; - long long y; - int neg = 0; - - c = shgetc(f); - if (c=='+' || c=='-') { - neg = (c=='-'); - c = shgetc(f); - if (c-'0'>=10U && pok) shunget(f); - } - if (c-'0'>=10U && c!='_') { - shunget(f); - return LLONG_MIN; - } - for (x=0; ; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c-'0'<10U && x>16) | 1ULL<<48; - yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; - xlo = ux.i2.lo; - ylo = uy.i2.lo; - for (; ex > ey; ex--) { - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi|lo) == 0) { - //return 0*x; - float128_t result; - f128M_mul(&zero, &x, &result); - return result; - } - xhi = 2*hi + (lo>>63); - xlo = 2*lo; - } else { - xhi = 2*xhi + (xlo>>63); - xlo = 2*xlo; - } - } - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi|lo) == 0) { - //return 0*x; - float128_t result; - f128M_mul(&zero, &x, &result); - return result; - } - xhi = hi; - xlo = lo; - } - for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); - ux.i2.hi = xhi; - ux.i2.lo = xlo; - - /* scale result */ - if (ex <= 0) { - ux.i.se = (ex+120)|sx; - //ux.f *= 0x1p-120f; - mul_eq_f128_float(&ux.f, 0x1p-120f); - } else - ux.i.se = ex|sx; - return ux.f; -} - -static float128_t int_mul_f128_cast_u32(int sign, uint32_t x0) { - float128_t x0_f128; - ui32_to_f128M(x0, &x0_f128); - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t result; - f128M_mul(&sign_f128, &x0_f128, &result); - return result; -} - -static float128_t triple_divide(int sign, uint32_t x0, int p10s) { - float128_t part1 = int_mul_f128_cast_u32(sign, x0); - float128_t p10s_f128; - i32_to_f128M(p10s, &p10s_f128); - float128_t result; - f128M_div(&part1, &p10s_f128, &result); - return result; -} - -static float128_t triple_multiply(int sign, uint32_t x0, int p10s) { - float128_t part1 = int_mul_f128_cast_u32(sign, x0); - float128_t p10s_f128; - i32_to_f128M(p10s, &p10s_f128); - float128_t result; - f128M_mul(&part1, &p10s_f128, &result); - return result; -} - -static void mul_eq_f128_int(float128_t *y, int sign) { - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t new_value; - f128M_mul(y, &sign_f128, &new_value); - *y = new_value; -} - -static float128_t make_f128(uint64_t hi, uint64_t lo) { - union ldshape ux; - ux.i2.hi = hi; - ux.i2.lo = lo; - return ux.f; -} - -static void mul_eq_f128_f128(float128_t *a, float128_t b) { - float128_t new_value; - f128M_mul(a, &b, &new_value); - *a = new_value; -} - -static void add_eq_f128_dbl(float128_t *a, double b) { - float64_t b_f64; - memcpy(&b_f64, &b, sizeof(double)); - - float128_t b_f128; - f64_to_f128M(b_f64, &b_f128); - - float128_t new_value; - f128M_add(a, &b_f128, &new_value); - *a = new_value; -} - -static float128_t scalbnf128(float128_t x, int n) -{ - union ldshape u; - - if (n > 16383) { - //x *= 0x1p16383q; - mul_eq_f128_f128(&x, make_f128(0x7ffe000000000000, 0x0000000000000000)); - n -= 16383; - if (n > 16383) { - //x *= 0x1p16383q; - mul_eq_f128_f128(&x, make_f128(0x7ffe000000000000, 0x0000000000000000)); - n -= 16383; - if (n > 16383) - n = 16383; - } - } else if (n < -16382) { - //x *= 0x1p-16382q * 0x1p113q; - { - float128_t mul_result; - float128_t a = make_f128(0x0001000000000000, 0x0000000000000000); - float128_t b = make_f128(0x4070000000000000, 0x0000000000000000); - f128M_mul(&a, &b, &mul_result); - mul_eq_f128_f128(&x, mul_result); - } - n += 16382 - 113; - if (n < -16382) { - //x *= 0x1p-16382q * 0x1p113q; - { - float128_t mul_result; - float128_t a = make_f128(0x0001000000000000, 0x0000000000000000); - float128_t b = make_f128(0x4070000000000000, 0x0000000000000000); - f128M_mul(&a, &b, &mul_result); - mul_eq_f128_f128(&x, mul_result); - } - n += 16382 - 113; - if (n < -16382) - n = -16382; - } - } - //u.f = 1.0; - ui32_to_f128M(1, &u.f); - u.i.se = 0x3fff + n; - mul_eq_f128_f128(&x, u.f); - return x; -} - -static float128_t fabsf128(float128_t x) -{ - union ldshape u = {x}; - - u.i.se &= 0x7fff; - return u.f; -} - -static float128_t decfloat(struct MuslFILE *f, int c, int bits, int emin, int sign, int pok) -{ - uint32_t x[KMAX]; - static const uint32_t th[] = { LD_B1B_MAX }; - int i, j, k, a, z; - long long lrp=0, dc=0; - long long e10=0; - int lnz = 0; - int gotdig = 0, gotrad = 0; - int rp; - int e2; - int emax = -emin-bits+3; - int denormal = 0; - float128_t y; - float128_t zero; - ui32_to_f128M(0, &zero); - float128_t frac=zero; - float128_t bias=zero; - static const int p10s[] = { 10, 100, 1000, 10000, - 100000, 1000000, 10000000, 100000000 }; - - j=0; - k=0; - - /* Don't let leading zeros/underscores consume buffer space */ - for (; ; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c=='0') { - gotdig=1; - } else { - break; - } - } - - if (c=='.') { - gotrad = 1; - for (c = shgetc(f); ; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c=='0') { - gotdig=1; - lrp--; - } else { - break; - } - } - } - - x[0] = 0; - for (; c-'0'<10U || c=='.' || c=='_'; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c == '.') { - if (gotrad) break; - gotrad = 1; - lrp = dc; - } else if (k < KMAX-3) { - dc++; - if (c!='0') lnz = dc; - if (j) x[k] = x[k]*10 + c-'0'; - else x[k] = c-'0'; - if (++j==9) { - k++; - j=0; - } - gotdig=1; - } else { - dc++; - if (c!='0') { - lnz = (KMAX-4)*9; - x[KMAX-4] |= 1; - } - } - } - if (!gotrad) lrp=dc; - - if (gotdig && (c|32)=='e') { - e10 = scanexp(f, pok); - if (e10 == LLONG_MIN) { - if (pok) { - shunget(f); - } else { - shlim(f, 0); - return zero; - } - e10 = 0; - } - lrp += e10; - } else if (c>=0) { - shunget(f); - } - if (!gotdig) { - errno = EINVAL; - shlim(f, 0); - return zero; - } - - /* Handle zero specially to avoid nasty special cases later */ - if (!x[0]) { - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - - /* Optimize small integers (w/no exponent) and over/under-flow */ - if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) { - //return sign * (float128_t)x[0]; - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t x0_f128; - ui32_to_f128M(x[0], &x0_f128); - float128_t result; - f128M_mul(&sign_f128, &x0_f128, &result); - return result; - } - if (lrp > -emin/2) { - errno = ERANGE; - //return sign * LDBL_MAX * LDBL_MAX; - return zero; - } - if (lrp < emin-2*LDBL_MANT_DIG) { - errno = ERANGE; - //return sign * LDBL_MIN * LDBL_MIN; - return zero; - } - - /* Align incomplete final B1B digit */ - if (j) { - for (; j<9; j++) x[k]*=10; - k++; - j=0; - } - - a = 0; - z = k; - e2 = 0; - rp = lrp; - - /* Optimize small to mid-size integers (even in exp. notation) */ - if (lnz<9 && lnz<=rp && rp < 18) { - if (rp == 9) { - //return sign * (float128_t)(x[0]); - return int_mul_f128_cast_u32(sign, x[0]); - } - if (rp < 9) { - //return sign * (float128_t)(x[0]) / p10s[8-rp]; - return triple_divide(sign, x[0], p10s[8-rp]); - } - int bitlim = bits-3*(int)(rp-9); - if (bitlim>30 || x[0]>>bitlim==0) - //return sign * (float128_t)(x[0]) * p10s[rp-10]; - return triple_multiply(sign, x[0], p10s[rp-10]); - } - - /* Drop trailing zeros */ - for (; !x[z-1]; z--); - - /* Align radix point to B1B digit boundary */ - if (rp % 9) { - int rpm9 = rp>=0 ? rp%9 : rp%9+9; - int p10 = p10s[8-rpm9]; - uint32_t carry = 0; - for (k=a; k!=z; k++) { - uint32_t tmp = x[k] % p10; - x[k] = x[k]/p10 + carry; - carry = 1000000000/p10 * tmp; - if (k==a && !x[k]) { - a = (a+1 & MASK); - rp -= 9; - } - } - if (carry) x[z++] = carry; - rp += 9-rpm9; - } - - /* Upscale until desired number of bits are left of radix point */ - while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a] 1000000000) { - carry = tmp / 1000000000; - x[k] = tmp % 1000000000; - } else { - carry = 0; - x[k] = tmp; - } - if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; - if (k==a) break; - } - if (carry) { - rp += 9; - a = (a-1 & MASK); - if (a == z) { - z = (z-1 & MASK); - x[z-1 & MASK] |= x[z]; - } - x[a] = carry; - } - } - - /* Downscale until exactly number of bits are left of radix point */ - for (;;) { - uint32_t carry = 0; - int sh = 1; - for (i=0; i th[i]) break; - } - if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; - /* FIXME: find a way to compute optimal sh */ - if (rp > 9+9*LD_B1B_DIG) sh = 9; - e2 += sh; - for (k=a; k!=z; k=(k+1 & MASK)) { - uint32_t tmp = x[k] & (1<>sh) + carry; - carry = (1000000000>>sh) * tmp; - if (k==a && !x[k]) { - a = (a+1 & MASK); - i--; - rp -= 9; - } - } - if (carry) { - if ((z+1 & MASK) != a) { - x[z] = carry; - z = (z+1 & MASK); - } else x[z-1 & MASK] |= 1; - } - } - - /* Assemble desired bits into floating point variable */ - for (y=zero,i=0; i LDBL_MANT_DIG+e2-emin) { - bits = LDBL_MANT_DIG+e2-emin; - if (bits<0) bits=0; - denormal = 1; - } - - /* Calculate bias term to force rounding, move out lower bits */ - if (bits < LDBL_MANT_DIG) { - bias = copysignf128(dbl_to_f128(scalbn(1, 2*LDBL_MANT_DIG-bits-1)), y); - frac = fmodf128(y, dbl_to_f128(scalbn(1, LDBL_MANT_DIG-bits))); - //y -= frac; - { - float128_t new_value; - f128M_sub(&y, &frac, &new_value); - y = new_value; - } - //y += bias; - { - float128_t new_value; - f128M_add(&y, &frac, &new_value); - y = new_value; - } - } - - /* Process tail of decimal input so it can affect rounding */ - if ((a+i & MASK) != z) { - uint32_t t = x[a+i & MASK]; - if (t < 500000000 && (t || (a+i+1 & MASK) != z)) { - //frac += 0.25*sign; - add_eq_f128_dbl(&frac, 0.25*sign); - } else if (t > 500000000) { - //frac += 0.75*sign; - add_eq_f128_dbl(&frac, 0.75*sign); - } else if (t == 500000000) { - if ((a+i+1 & MASK) == z) { - //frac += 0.5*sign; - add_eq_f128_dbl(&frac, 0.5*sign); - } else { - //frac += 0.75*sign; - add_eq_f128_dbl(&frac, 0.75*sign); - } - } - //if (LDBL_MANT_DIG-bits >= 2 && !fmodf128(frac, 1)) - if (LDBL_MANT_DIG-bits >= 2) { - float128_t one; - ui32_to_f128M(1, &one); - float128_t mod_result = fmodf128(frac, one); - if (f128M_eq(&mod_result, &zero)) { - //frac++; - add_eq_f128_dbl(&frac, 1.0); - } - } - } - - //y += frac; - { - float128_t new_value; - f128M_add(&y, &frac, &new_value); - y = new_value; - } - //y -= bias; - { - float128_t new_value; - f128M_sub(&y, &bias, &new_value); - y = new_value; - } - - if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) { - //if (fabsf128(y) >= 0x1p113) - float128_t abs_y = fabsf128(y); - float128_t mant_f128 = make_f128(0x4070000000000000, 0x0000000000000000); - if (!f128M_lt(&abs_y, &mant_f128)) { - if (denormal && bits==LDBL_MANT_DIG+e2-emin) - denormal = 0; - //y *= 0.5; - { - float128_t point_5 = dbl_to_f128(0.5); - float128_t new_value; - f128M_mul(&y, &point_5, &new_value); - y = new_value; - } - - e2++; - } - if (e2+LDBL_MANT_DIG>emax || (denormal && !f128M_eq(&frac, &zero))) - errno = ERANGE; - } - - return scalbnf128(y, e2); -} - -static float128_t hexfloat(struct MuslFILE *f, int bits, int emin, int sign, int pok) -{ - float128_t zero; - ui32_to_f128M(0, &zero); - float128_t one; - ui32_to_f128M(1, &one); - float128_t sixteen; - ui32_to_f128M(16, &sixteen); - float128_t point_5 = dbl_to_f128(0.5); - - uint32_t x = 0; - float128_t y = zero; - float128_t scale = one; - float128_t bias = zero; - int gottail = 0, gotrad = 0, gotdig = 0; - long long rp = 0; - long long dc = 0; - long long e2 = 0; - int d; - int c; - - c = shgetc(f); - - /* Skip leading zeros/underscores */ - for (; c=='0' || c=='_'; c = shgetc(f)) gotdig = 1; - - if (c=='.') { - gotrad = 1; - c = shgetc(f); - /* Count zeros after the radix point before significand */ - for (rp=0; ; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c == '0') { - gotdig = 1; - rp--; - } else { - break; - } - } - } - - for (; c-'0'<10U || (c|32)-'a'<6U || c=='.' || c=='_'; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c=='.') { - if (gotrad) break; - rp = dc; - gotrad = 1; - } else { - gotdig = 1; - if (c > '9') d = (c|32)+10-'a'; - else d = c-'0'; - if (dc<8) { - x = x*16 + d; - } else if (dc < LDBL_MANT_DIG/4+1) { - //y += d*(scale/=16); - { - float128_t divided; - f128M_div(&scale, &sixteen, ÷d); - scale = divided; - float128_t d_f128; - i32_to_f128M(d, &d_f128); - float128_t add_op; - f128M_mul(&d_f128, &scale, &add_op); - float128_t new_y; - f128M_add(&y, &add_op, &new_y); - y = new_y; - } - } else if (d && !gottail) { - //y += 0.5*scale; - { - float128_t add_op; - f128M_mul(&point_5, &scale, &add_op); - float128_t new_y; - f128M_add(&y, &add_op, &new_y); - y = new_y; - } - gottail = 1; - } - dc++; - } - } - if (!gotdig) { - shunget(f); - if (pok) { - shunget(f); - if (gotrad) shunget(f); - } else { - shlim(f, 0); - } - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - if (!gotrad) rp = dc; - while (dc<8) x *= 16, dc++; - if ((c|32)=='p') { - e2 = scanexp(f, pok); - if (e2 == LLONG_MIN) { - if (pok) { - shunget(f); - } else { - shlim(f, 0); - return zero; - } - e2 = 0; - } - } else { - shunget(f); - } - e2 += 4*rp - 32; - - if (!x) { - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - if (e2 > -emin) { - errno = ERANGE; - //return sign * LDBL_MAX * LDBL_MAX; - return zero; - } - if (e2 < emin-2*LDBL_MANT_DIG) { - errno = ERANGE; - //return sign * LDBL_MIN * LDBL_MIN; - return zero; - } - - while (x < 0x80000000) { - //if (y>=0.5) - if (!f128M_lt(&y, &point_5)) { - x += x + 1; - //y += y - 1; - { - float128_t minus_one; - f128M_sub(&y, &one, &minus_one); - float128_t new_y; - f128M_add(&y, &minus_one, &new_y); - y = new_y; - } - } else { - x += x; - //y += y; - { - float128_t new_y; - f128M_add(&y, &y, &new_y); - y = new_y; - } - } - e2--; - } - - if (bits > 32+e2-emin) { - bits = 32+e2-emin; - if (bits<0) bits=0; - } - - if (bits < LDBL_MANT_DIG) { - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - bias = copysignf128(dbl_to_f128(scalbn(1, 32+LDBL_MANT_DIG-bits-1)), sign_f128); - } - - //if (bits<32 && y && !(x&1)) x++, y=0; - if (bits<32 && !f128M_eq(&y, &zero) && !(x&1)) x++, y=zero; - - //y = bias + sign*(float128_t)x + sign*y; - { - float128_t x_f128; - ui32_to_f128M(x, &x_f128); - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t sign_mul_x; - f128M_mul(&sign_f128, &x_f128, &sign_mul_x); - float128_t sign_mul_y; - f128M_mul(&sign_f128, &y, &sign_mul_y); - float128_t bias_op; - f128M_add(&bias, &sign_mul_x, &bias_op); - float128_t new_y; - f128M_add(&bias_op, &sign_mul_y, &new_y); - y = new_y; - } - //y -= bias; - { - float128_t new_y; - f128M_sub(&y, &bias, &new_y); - y = new_y; - } - - if (f128M_eq(&y, &zero)) errno = ERANGE; - - return scalbnf128(y, e2); -} - -static int isspace(int c) -{ - return c == ' ' || (unsigned)c-'\t' < 5; -} - -static inline float128_t makeInf128(void) { - union ldshape ux; - ux.i2.hi = 0x7fff000000000000UL; - ux.i2.lo = 0x0UL; - return ux.f; -} - -static inline float128_t makeNaN128(void) { - uint64_t rand = 0UL; - union ldshape ux; - ux.i2.hi = 0x7fff000000000000UL | (rand & 0xffffffffffffUL); - ux.i2.lo = 0x0UL; - return ux.f; -} - -float128_t __floatscan(struct MuslFILE *f, int prec, int pok) -{ - int sign = 1; - size_t i; - int bits = LDBL_MANT_DIG; - int emin = LDBL_MIN_EXP-bits; - int c; - - while (isspace((c=shgetc(f)))); - - if (c=='+' || c=='-') { - sign -= 2*(c=='-'); - c = shgetc(f); - } - - for (i=0; i<8 && (c|32)=="infinity"[i]; i++) - if (i<7) c = shgetc(f); - if (i==3 || i==8 || (i>3 && pok)) { - if (i!=8) { - shunget(f); - if (pok) for (; i>3; i--) shunget(f); - } - //return sign * INFINITY; - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t infinity_f128 = makeInf128(); - float128_t result; - f128M_mul(&sign_f128, &infinity_f128, &result); - return result; - } - if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) - if (i<2) c = shgetc(f); - if (i==3) { - if (shgetc(f) != '(') { - shunget(f); - return makeNaN128(); - } - for (i=1; ; i++) { - c = shgetc(f); - if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') - continue; - if (c==')') return makeNaN128(); - shunget(f); - if (!pok) { - errno = EINVAL; - shlim(f, 0); - float128_t zero; - ui32_to_f128M(0, &zero); - return zero; - } - while (i--) shunget(f); - return makeNaN128(); - } - return makeNaN128(); - } - - if (i) { - shunget(f); - errno = EINVAL; - shlim(f, 0); - float128_t zero; - ui32_to_f128M(0, &zero); - return zero; - } - - if (c=='0') { - c = shgetc(f); - if ((c|32) == 'x') - return hexfloat(f, bits, emin, sign, pok); - shunget(f); - c = '0'; - } - - return decfloat(f, c, bits, emin, sign, pok); -} - -float128_t parse_f128(const char *s, char **p) { - struct MuslFILE f; - sh_fromstring(&f, s); - shlim(&f, 0); - float128_t y = __floatscan(&f, 2, 1); - off_t cnt = shcnt(&f); - if (p) *p = cnt ? (char *)s + cnt : (char *)s; - return y; -} diff --git a/src/stage1/parse_f128.h b/src/stage1/parse_f128.h deleted file mode 100644 index 82cdf6c9a0bf..000000000000 --- a/src/stage1/parse_f128.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_PARSE_F128_H -#define ZIG_PARSE_F128_H - -#include "softfloat_types.h" - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -ZIG_EXTERN_C float128_t parse_f128(const char *s, char **p); - -#endif diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp deleted file mode 100644 index eaa15c47b0c3..000000000000 --- a/src/stage1/parser.cpp +++ /dev/null @@ -1,3603 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "parser.hpp" -#include "errmsg.hpp" -#include "analyze.hpp" - -#include -#include -#include -#include - -struct ParseContext { - Buf *buf; - // Shortcut to `owner->data.structure.root_struct->token_ids`. - TokenId *token_ids; - // Shortcut to `owner->data.structure.root_struct->token_locs`. - TokenLoc *token_locs; - ZigType *owner; - TokenIndex current_token; - ErrColor err_color; - // Shortcut to `owner->data.structure.root_struct->token_count`. - uint32_t token_count; -}; - -struct PtrPayload { - TokenIndex asterisk; - TokenIndex payload; -}; - -struct PtrIndexPayload { - TokenIndex asterisk; - TokenIndex payload; - TokenIndex index; -}; - -static AstNode *ast_parse_root(ParseContext *pc); -static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc); -static AstNode *ast_parse_test_decl(ParseContext *pc); -static AstNode *ast_parse_top_level_comptime(ParseContext *pc); -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, - TokenIndex doc_comments); -static AstNode *ast_parse_fn_proto(ParseContext *pc); -static AstNode *ast_parse_var_decl(ParseContext *pc); -static AstNode *ast_parse_container_field(ParseContext *pc); -static AstNode *ast_parse_statement(ParseContext *pc); -static AstNode *ast_parse_if_statement(ParseContext *pc); -static AstNode *ast_parse_labeled_statement(ParseContext *pc); -static AstNode *ast_parse_loop_statement(ParseContext *pc); -static AstNode *ast_parse_for_statement(ParseContext *pc); -static AstNode *ast_parse_while_statement(ParseContext *pc); -static AstNode *ast_parse_block_expr_statement(ParseContext *pc); -static AstNode *ast_parse_block_expr(ParseContext *pc); -static AstNode *ast_parse_assign_expr(ParseContext *pc); -static AstNode *ast_parse_expr(ParseContext *pc); -static AstNode *ast_parse_bool_or_expr(ParseContext *pc); -static AstNode *ast_parse_bool_and_expr(ParseContext *pc); -static AstNode *ast_parse_compare_expr(ParseContext *pc); -static AstNode *ast_parse_bitwise_expr(ParseContext *pc); -static AstNode *ast_parse_bit_shift_expr(ParseContext *pc); -static AstNode *ast_parse_addition_expr(ParseContext *pc); -static AstNode *ast_parse_multiply_expr(ParseContext *pc); -static AstNode *ast_parse_prefix_expr(ParseContext *pc); -static AstNode *ast_parse_primary_expr(ParseContext *pc); -static AstNode *ast_parse_if_expr(ParseContext *pc); -static AstNode *ast_parse_block(ParseContext *pc); -static AstNode *ast_parse_loop_expr(ParseContext *pc); -static AstNode *ast_parse_for_expr(ParseContext *pc); -static AstNode *ast_parse_while_expr(ParseContext *pc); -static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc); -static AstNode *ast_parse_init_list(ParseContext *pc); -static AstNode *ast_parse_type_expr(ParseContext *pc); -static AstNode *ast_parse_error_union_expr(ParseContext *pc); -static AstNode *ast_parse_suffix_expr(ParseContext *pc); -static AstNode *ast_parse_primary_type_expr(ParseContext *pc); -static AstNode *ast_parse_container_decl(ParseContext *pc); -static AstNode *ast_parse_error_set_decl(ParseContext *pc); -static AstNode *ast_parse_grouped_expr(ParseContext *pc); -static AstNode *ast_parse_if_type_expr(ParseContext *pc); -static AstNode *ast_parse_labeled_type_expr(ParseContext *pc); -static AstNode *ast_parse_loop_type_expr(ParseContext *pc); -static AstNode *ast_parse_for_type_expr(ParseContext *pc); -static AstNode *ast_parse_while_type_expr(ParseContext *pc); -static AstNode *ast_parse_switch_expr(ParseContext *pc); -static AstNode *ast_parse_asm_expr(ParseContext *pc); -static AstNode *ast_parse_anon_lit(ParseContext *pc); -static AstNode *ast_parse_asm_output(ParseContext *pc); -static AsmOutput *ast_parse_asm_output_item(ParseContext *pc); -static AstNode *ast_parse_asm_input(ParseContext *pc); -static AsmInput *ast_parse_asm_input_item(ParseContext *pc); -static AstNode *ast_parse_asm_clobbers(ParseContext *pc); -static TokenIndex ast_parse_break_label(ParseContext *pc); -static TokenIndex ast_parse_block_label(ParseContext *pc); -static AstNode *ast_parse_field_init(ParseContext *pc); -static AstNode *ast_parse_while_continue_expr(ParseContext *pc); -static AstNode *ast_parse_link_section(ParseContext *pc); -static AstNode *ast_parse_callconv(ParseContext *pc); -static AstNode *ast_parse_param_decl(ParseContext *pc); -static AstNode *ast_parse_param_type(ParseContext *pc); -static AstNode *ast_parse_if_prefix(ParseContext *pc); -static AstNode *ast_parse_while_prefix(ParseContext *pc); -static AstNode *ast_parse_for_prefix(ParseContext *pc); -static TokenIndex ast_parse_payload(ParseContext *pc); -static Optional ast_parse_ptr_payload(ParseContext *pc); -static Optional ast_parse_ptr_index_payload(ParseContext *pc); -static AstNode *ast_parse_switch_prong(ParseContext *pc); -static AstNode *ast_parse_switch_case(ParseContext *pc); -static AstNode *ast_parse_switch_item(ParseContext *pc); -static AstNode *ast_parse_assign_op(ParseContext *pc); -static AstNode *ast_parse_compare_op(ParseContext *pc); -static AstNode *ast_parse_bitwise_op(ParseContext *pc); -static AstNode *ast_parse_bit_shift_op(ParseContext *pc); -static AstNode *ast_parse_addition_op(ParseContext *pc); -static AstNode *ast_parse_multiply_op(ParseContext *pc); -static AstNode *ast_parse_prefix_op(ParseContext *pc); -static AstNode *ast_parse_prefix_type_op(ParseContext *pc); -static AstNode *ast_parse_suffix_op(ParseContext *pc); -static AstNode *ast_parse_fn_call_arguments(ParseContext *pc); -static AstNode *ast_parse_array_type_start(ParseContext *pc); -static AstNode *ast_parse_ptr_type_start(ParseContext *pc); -static AstNode *ast_parse_container_decl_auto(ParseContext *pc); -static AstNode *ast_parse_container_decl_type(ParseContext *pc); -static AstNode *ast_parse_byte_align(ParseContext *pc); - -ATTRIBUTE_NORETURN -static void ast_error_offset(RootStruct *root_struct, ErrColor err_color, - TokenIndex token, size_t bad_index, Buf *msg) -{ - assert(token < root_struct->token_count); - uint32_t byte_offset = root_struct->token_locs[token].offset; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, - byte_offset + bad_index, buf_ptr(root_struct->source_code), msg); - - print_err_msg(err, err_color); - exit(EXIT_FAILURE); -} - -ATTRIBUTE_PRINTF(3, 4) -ATTRIBUTE_NORETURN -static void ast_error(ParseContext *pc, TokenIndex token, const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *msg = buf_vprintf(format, ap); - va_end(ap); - - RootStruct *root_struct = pc->owner->data.structure.root_struct; - ast_error_offset(root_struct, pc->err_color, token, 0, msg); -} - -ATTRIBUTE_NORETURN -static void ast_invalid_token_error(ParseContext *pc, TokenIndex token) { - ast_error(pc, token, "invalid token: '%s'", token_name(pc->token_ids[token])); -} - -static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { - AstNode *node = heap::c_allocator.create(); - node->type = type; - node->owner = pc->owner; - return node; -} - -static AstNode *ast_create_node(ParseContext *pc, NodeType type, TokenIndex first_token) { - assert(first_token); - AstNode *node = ast_create_node_no_line_info(pc, type); - node->main_token = first_token; - return node; -} - -static AstNode *ast_create_node_copy_line_info(ParseContext *pc, NodeType type, AstNode *from) { - assert(from); - AstNode *node = ast_create_node_no_line_info(pc, type); - node->main_token = from->main_token; - return node; -} - -static TokenIndex peek_token(ParseContext *pc) { - return pc->current_token; -} - -static TokenIndex eat_token(ParseContext *pc) { - TokenIndex res = peek_token(pc); - pc->current_token += 1; - return res; -} - -static TokenIndex eat_token_if(ParseContext *pc, TokenId id) { - TokenIndex res = peek_token(pc); - if (pc->token_ids[res] == id) { - return eat_token(pc); - } - - return 0; -} - -static TokenIndex expect_token(ParseContext *pc, TokenId id) { - TokenIndex res = eat_token(pc); - TokenId actual_id = pc->token_ids[res]; - if (actual_id != id) - ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(actual_id)); - - return res; -} - -static void put_back_token(ParseContext *pc) { - pc->current_token -= 1; -} - -static Buf *token_buf(ParseContext *pc, TokenIndex token) { - Error err; - - if (token == 0) - return nullptr; - - RootStruct *root_struct = pc->owner->data.structure.root_struct; - if (root_struct->token_ids[token] == TokenIdIdentifier) { - return token_identifier_buf(root_struct, token); - } else if (root_struct->token_ids[token] == TokenIdStringLiteral) { - assert(root_struct->token_ids[token] == TokenIdStringLiteral); - const char *source = buf_ptr(root_struct->source_code); - size_t byte_offset = root_struct->token_locs[token].offset; - size_t bad_index; - Buf *str = buf_alloc(); - if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { - ast_error_offset(root_struct, pc->err_color, token, bad_index, - buf_create_from_str("invalid string literal character")); - } - return str; - } else { - zig_unreachable(); - } -} - -static AstNode *token_identifier(ParseContext *pc, TokenIndex token) { - assert(pc->token_ids[token] == TokenIdIdentifier); - return ast_create_node(pc, NodeTypeIdentifier, token); -} - -// (Rule SEP)* Rule? -template -static ZigList ast_parse_list(ParseContext *pc, TokenId sep, T *(*parser)(ParseContext*)) { - ZigList res = {}; - while (true) { - T *curr = parser(pc); - if (curr == nullptr) - break; - - res.append(curr); - if (eat_token_if(pc, sep) == 0) - break; - } - - return res; -} - -static AstNode *ast_expect(ParseContext *pc, AstNode *(*parser)(ParseContext*)) { - AstNode *res = parser(pc); - if (res == nullptr) - ast_invalid_token_error(pc, peek_token(pc)); - return res; -} - -enum BinOpChain { - BinOpChainOnce, - BinOpChainInf, -}; - -// Op* Child -static AstNode *ast_parse_prefix_op_expr( - ParseContext *pc, - AstNode *(*op_parser)(ParseContext *), - AstNode *(*child_parser)(ParseContext *) -) { - AstNode *res = nullptr; - AstNode **right = &res; - while (true) { - AstNode *prefix = op_parser(pc); - if (prefix == nullptr) - break; - - *right = prefix; - switch (prefix->type) { - case NodeTypePrefixOpExpr: - right = &prefix->data.prefix_op_expr.primary_expr; - break; - case NodeTypeReturnExpr: - right = &prefix->data.return_expr.expr; - break; - case NodeTypeAwaitExpr: - right = &prefix->data.await_expr.expr; - break; - case NodeTypeAnyFrameType: - right = &prefix->data.anyframe_type.payload_type; - break; - case NodeTypeArrayType: - right = &prefix->data.array_type.child_type; - break; - case NodeTypeInferredArrayType: - right = &prefix->data.inferred_array_type.child_type; - break; - case NodeTypePointerType: { - // We might get two pointers from *_ptr_type_start - AstNode *child = prefix->data.pointer_type.op_expr; - if (child == nullptr) - child = prefix; - right = &child->data.pointer_type.op_expr; - break; - } - default: - zig_unreachable(); - } - } - - // If we have already consumed a token, and determined that - // this node is a prefix op, then we expect that the node has - // a child. - if (res != nullptr) { - *right = ast_expect(pc, child_parser); - } else { - // Otherwise, if we didn't consume a token, then we can return - // null, if the child expr did. - *right = child_parser(pc); - if (*right == nullptr) - return nullptr; - } - - return res; -} - -// Child (Op Child)(*/?) -static AstNode *ast_parse_bin_op_expr( - ParseContext *pc, - BinOpChain chain, - AstNode *(*op_parse)(ParseContext*), - AstNode *(*child_parse)(ParseContext*) -) { - AstNode *res = child_parse(pc); - if (res == nullptr) - return nullptr; - - do { - AstNode *op = op_parse(pc); - if (op == nullptr) - break; - - AstNode *left = res; - AstNode *right = ast_expect(pc, child_parse); - res = op; - switch (op->type) { - case NodeTypeBinOpExpr: - op->data.bin_op_expr.op1 = left; - op->data.bin_op_expr.op2 = right; - break; - case NodeTypeCatchExpr: - op->data.unwrap_err_expr.op1 = left; - op->data.unwrap_err_expr.op2 = right; - break; - default: - zig_unreachable(); - } - } while (chain == BinOpChainInf); - - return res; -} - -// IfPrefix Body (KEYWORD_else Payload? Body)? -static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_if_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, body_parser); - } - - assert(res->type == NodeTypeIfOptional); - if (err_payload != 0) { - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfErrorExpr; - res->data.if_err_expr.target_node = old.target_node; - res->data.if_err_expr.var_is_ptr = old.var_is_ptr; - res->data.if_err_expr.var_symbol = old.var_symbol; - res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); - res->data.if_err_expr.else_node = else_body; - return res; - } - - if (res->data.test_expr.var_symbol != nullptr) { - res->data.test_expr.then_node = body; - res->data.test_expr.else_node = else_body; - return res; - } - - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfBoolExpr; - res->data.if_bool_expr.condition = old.target_node; - res->data.if_bool_expr.then_block = body; - res->data.if_bool_expr.else_node = else_body; - return res; -} - -// KEYWORD_inline? (ForLoop / WhileLoop) -static AstNode *ast_parse_loop_expr_helper( - ParseContext *pc, - AstNode *(*for_parser)(ParseContext *), - AstNode *(*while_parser)(ParseContext *) -) { - TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); - AstNode *for_expr = for_parser(pc); - if (for_expr != nullptr) { - assert(for_expr->type == NodeTypeForExpr); - for_expr->data.for_expr.is_inline = inline_token != 0; - return for_expr; - } - - AstNode *while_expr = while_parser(pc); - if (while_expr != nullptr) { - assert(while_expr->type == NodeTypeWhileExpr); - while_expr->data.while_expr.is_inline = inline_token != 0; - return while_expr; - } - - if (inline_token != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// ForPrefix Body (KEYWORD_else Body)? -static AstNode *ast_parse_for_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_for_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) - else_body = ast_expect(pc, body_parser); - - assert(res->type == NodeTypeForExpr); - res->data.for_expr.body = body; - res->data.for_expr.else_node = else_body; - return res; -} - -// WhilePrefix Body (KEYWORD_else Payload? Body)? -static AstNode *ast_parse_while_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_while_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, body_parser); - } - - assert(res->type == NodeTypeWhileExpr); - res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(pc, err_payload); - res->data.while_expr.else_node = else_body; - return res; -} - -template -AstNode *ast_parse_bin_op_simple(ParseContext *pc) { - TokenIndex op_token = eat_token_if(pc, id); - if (op_token == 0) - return nullptr; - - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; -} - -AstNode *ast_parse(Buf *buf, ZigType *owner, ErrColor err_color) { - RootStruct *root_struct = owner->data.structure.root_struct; - - ParseContext pc = {}; - pc.err_color = err_color; - pc.owner = owner; - pc.buf = buf; - pc.token_ids = root_struct->token_ids; - pc.token_locs = root_struct->token_locs; - pc.token_count = root_struct->token_count; - pc.current_token = 1; // Skip over the first (invalid) token. - return ast_parse_root(&pc); -} - -// Root <- skip ContainerMembers eof -static AstNode *ast_parse_root(ParseContext *pc) { - TokenIndex first = peek_token(pc); - AstNodeContainerDecl members = ast_parse_container_members(pc); - if (pc->current_token != pc->token_count - 1) - ast_invalid_token_error(pc, peek_token(pc)); - - AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first); - node->data.container_decl.fields = members.fields; - node->data.container_decl.decls = members.decls; - node->data.container_decl.layout = ContainerLayoutAuto; - node->data.container_decl.kind = ContainerKindStruct; - node->data.container_decl.is_root = true; - node->data.container_decl.doc_comments = members.doc_comments; - - return node; -} - -static TokenIndex ast_parse_multi_tok(ParseContext *pc, TokenId token_id) { - TokenIndex first_token = eat_token_if(pc, token_id); - TokenIndex token = first_token; - while (token != 0) { - token = eat_token_if(pc, token_id); - } - return first_token; -} - -static TokenIndex ast_parse_doc_comments(ParseContext *pc) { - return ast_parse_multi_tok(pc, TokenIdDocComment); -} - -static TokenIndex ast_parse_container_doc_comments(ParseContext *pc) { - return ast_parse_multi_tok(pc, TokenIdContainerDocComment); -} - -enum ContainerFieldState { - // no fields have been seen - ContainerFieldStateNone, - // currently parsing fields - ContainerFieldStateSeen, - // saw fields and then a declaration after them - ContainerFieldStateEnd, -}; - -// ContainerMembers -// <- TestDecl ContainerMembers -// / TopLevelComptime ContainerMembers -// / KEYWORD_pub? TopLevelDecl ContainerMembers -// / ContainerField COMMA ContainerMembers -// / ContainerField -// / -static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { - AstNodeContainerDecl res = {}; - ContainerFieldState field_state = ContainerFieldStateNone; - TokenIndex first_token = 0; - res.doc_comments = ast_parse_container_doc_comments(pc); - for (;;) { - TokenIndex peeked_token = peek_token(pc); - - AstNode *test_decl = ast_parse_test_decl(pc); - if (test_decl != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(test_decl); - continue; - } - - AstNode *top_level_comptime = ast_parse_top_level_comptime(pc); - if (top_level_comptime != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(top_level_comptime); - continue; - } - - TokenIndex first_doc_token = ast_parse_doc_comments(pc); - - peeked_token = peek_token(pc); - - TokenIndex visib_token = eat_token_if(pc, TokenIdKeywordPub); - VisibMod visib_mod = (visib_token != 0) ? VisibModPub : VisibModPrivate; - - AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, first_doc_token); - if (top_level_decl != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(top_level_decl); - continue; - } - - if (visib_token != 0) { - ast_error(pc, peek_token(pc), "expected function or variable declaration after pub"); - } - - TokenIndex comptime_token = eat_token_if(pc, TokenIdKeywordCompTime); - - AstNode *container_field = ast_parse_container_field(pc); - if (container_field != nullptr) { - switch (field_state) { - case ContainerFieldStateNone: - field_state = ContainerFieldStateSeen; - break; - case ContainerFieldStateSeen: - break; - case ContainerFieldStateEnd: - ast_error(pc, first_token, "declarations are not allowed between container fields"); - } - - assert(container_field->type == NodeTypeStructField); - container_field->data.struct_field.doc_comments = first_doc_token; - container_field->data.struct_field.comptime_token = comptime_token; - res.fields.append(container_field); - if (eat_token_if(pc, TokenIdComma) != 0) { - continue; - } else { - break; - } - } - - break; - } - return res; -} - -// TestDecl <- KEYWORD_test STRINGLITERALSINGLE? Block -static AstNode *ast_parse_test_decl(ParseContext *pc) { - TokenIndex test = eat_token_if(pc, TokenIdKeywordTest); - if (test == 0) - return nullptr; - - TokenIndex name = eat_token_if(pc, TokenIdStringLiteral); - AstNode *block = ast_expect(pc, ast_parse_block); - AstNode *res = ast_create_node(pc, NodeTypeTestDecl, test); - res->data.test_decl.name = name ? token_buf(pc, name) : nullptr; - res->data.test_decl.body = block; - return res; -} - -// TopLevelComptime <- KEYWORD_comptime BlockExpr -static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime == 0) - return nullptr; - - // 1 token lookahead because it could be a comptime struct field - TokenIndex lbrace = peek_token(pc); - if (pc->token_ids[lbrace] != TokenIdLBrace) { - put_back_token(pc); - return nullptr; - } - - AstNode *block = ast_expect(pc, ast_parse_block_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = block; - return res; -} - -// TopLevelDecl -// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) -// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl -// / KEYWORD_use Expr SEMICOLON -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, - TokenIndex doc_comments) -{ - TokenIndex first = eat_token_if(pc, TokenIdKeywordExport); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordExtern); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordInline); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordNoInline); - if (first != 0) { - TokenIndex lib_name = 0; - if (pc->token_ids[first] == TokenIdKeywordExtern) - lib_name = eat_token_if(pc, TokenIdStringLiteral); - - if (pc->token_ids[first] != TokenIdKeywordNoInline && pc->token_ids[first] != TokenIdKeywordInline) { - TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - if (pc->token_ids[first] == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { - ast_error(pc, first, "extern variables have no initializers"); - } - var_decl->main_token = first; - var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; - var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = doc_comments; - var_decl->data.variable_declaration.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; - var_decl->data.variable_declaration.is_export = pc->token_ids[first] == TokenIdKeywordExport; - var_decl->data.variable_declaration.lib_name = token_buf(pc, lib_name); - return var_decl; - } - - if (thread_local_kw != 0) - put_back_token(pc); - } - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) { - AstNode *body = ast_parse_block(pc); - if (body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(fn_proto->type == NodeTypeFnProto); - fn_proto->main_token = first; - fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = doc_comments; - if (!fn_proto->data.fn_proto.is_extern) - fn_proto->data.fn_proto.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; - fn_proto->data.fn_proto.is_export = pc->token_ids[first] == TokenIdKeywordExport; - switch (pc->token_ids[first]) { - case TokenIdKeywordInline: - fn_proto->data.fn_proto.fn_inline = FnInlineAlways; - break; - case TokenIdKeywordNoInline: - fn_proto->data.fn_proto.fn_inline = FnInlineNever; - break; - default: - fn_proto->data.fn_proto.fn_inline = FnInlineAuto; - break; - } - fn_proto->data.fn_proto.lib_name = token_buf(pc, lib_name); - - AstNode *res = fn_proto; - if (body != nullptr) { - if (fn_proto->data.fn_proto.is_extern) { - ast_error(pc, first, "extern functions have no body"); - } - res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); - res->data.fn_def.fn_proto = fn_proto; - res->data.fn_def.body = body; - fn_proto->data.fn_proto.fn_def_node = res; - } - - return res; - } - - ast_invalid_token_error(pc, peek_token(pc)); - } - - TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = doc_comments; - var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; - return var_decl; - } - - if (thread_local_kw != 0) - put_back_token(pc); - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) { - AstNode *body = ast_parse_block(pc); - if (body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(fn_proto->type == NodeTypeFnProto); - fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = doc_comments; - AstNode *res = fn_proto; - if (body != nullptr) { - res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); - res->data.fn_def.fn_proto = fn_proto; - res->data.fn_def.body = body; - fn_proto->data.fn_proto.fn_def_node = res; - } - - return res; - } - - TokenIndex usingnamespace = eat_token_if(pc, TokenIdKeywordUsingNamespace); - if (usingnamespace != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdSemicolon); - - AstNode *res = ast_create_node(pc, NodeTypeUsingNamespace, usingnamespace); - res->data.using_namespace.visib_mod = visib_mod; - res->data.using_namespace.expr = expr; - return res; - } - - return nullptr; -} - -// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype / TypeExpr) -static AstNode *ast_parse_fn_proto(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordFn); - if (first == 0) { - return nullptr; - } - - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - expect_token(pc, TokenIdLParen); - ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_param_decl); - expect_token(pc, TokenIdRParen); - - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_link_section(pc); - AstNode *callconv_expr = ast_parse_callconv(pc); - TokenIndex exmark = 0; - AstNode *return_type = nullptr; - - exmark = eat_token_if(pc, TokenIdBang); - return_type = ast_parse_type_expr(pc); - if (return_type == nullptr) { - TokenIndex next = peek_token(pc); - ast_error( - pc, - next, - "expected return type (use 'void' to return nothing), found: '%s'", - token_name(pc->token_ids[next]) - ); - } - - AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); - res->data.fn_proto = {}; - res->data.fn_proto.name = token_buf(pc, identifier); - res->data.fn_proto.params = params; - res->data.fn_proto.align_expr = align_expr; - res->data.fn_proto.section_expr = section_expr; - res->data.fn_proto.callconv_expr = callconv_expr; - res->data.fn_proto.auto_err_set = exmark != 0; - res->data.fn_proto.return_type = return_type; - - for (size_t i = 0; i < params.length; i++) { - AstNode *param_decl = params.at(i); - assert(param_decl->type == NodeTypeParamDecl); - if (param_decl->data.param_decl.is_var_args) - res->data.fn_proto.is_var_args = true; - if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error(pc, first, "Function prototype have varargs as a none last parameter."); - } - return res; -} - -// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON -static AstNode *ast_parse_var_decl(ParseContext *pc) { - TokenIndex mut_kw = eat_token_if(pc, TokenIdKeywordConst); - if (mut_kw == 0) - mut_kw = eat_token_if(pc, TokenIdKeywordVar); - if (mut_kw == 0) - return nullptr; - - TokenIndex identifier = expect_token(pc, TokenIdIdentifier); - AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != 0) - type_expr = ast_expect(pc, ast_parse_type_expr); - - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_link_section(pc); - AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != 0) - expr = ast_expect(pc, ast_parse_expr); - - expect_token(pc, TokenIdSemicolon); - - AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); - res->data.variable_declaration.is_const = pc->token_ids[mut_kw] == TokenIdKeywordConst; - res->data.variable_declaration.symbol = token_buf(pc, identifier); - res->data.variable_declaration.type = type_expr; - res->data.variable_declaration.align_expr = align_expr; - res->data.variable_declaration.section_expr = section_expr; - res->data.variable_declaration.expr = expr; - return res; -} - -// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? -static AstNode *ast_parse_container_field(ParseContext *pc) { - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier == 0) - return nullptr; - - AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != 0) { - TokenIndex anytype_tok = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_tok != 0) { - type_expr = ast_create_node(pc, NodeTypeAnyTypeField, anytype_tok); - } else { - type_expr = ast_expect(pc, ast_parse_type_expr); - } - } - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != 0) - expr = ast_expect(pc, ast_parse_expr); - - AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); - res->data.struct_field.name = token_buf(pc, identifier); - res->data.struct_field.type = type_expr; - res->data.struct_field.value = expr; - res->data.struct_field.align_expr = align_expr; - return res; -} - -// Statement -// <- KEYWORD_comptime? VarDecl -// / KEYWORD_comptime BlockExprStatement -// / KEYWORD_nosuspend BlockExprStatement -// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) -// / KEYWORD_defer BlockExprStatement -// / KEYWORD_errdefer Payload? BlockExprStatement -// / IfStatement -// / LabeledStatement -// / SwitchExpr -// / AssignExpr SEMICOLON -static AstNode *ast_parse_statement(ParseContext *pc) { - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - var_decl->data.variable_declaration.is_comptime = comptime != 0; - return var_decl; - } - - if (comptime != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = statement; - return res; - } - - TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); - res->data.nosuspend_expr.expr = statement; - return res; - } - - TokenIndex suspend = eat_token_if(pc, TokenIdKeywordSuspend); - if (suspend != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeSuspend, suspend); - res->data.suspend.block = statement; - return res; - } - - TokenIndex defer = eat_token_if(pc, TokenIdKeywordDefer); - if (defer == 0) - defer = eat_token_if(pc, TokenIdKeywordErrdefer); - if (defer != 0) { - TokenIndex payload = (pc->token_ids[defer] == TokenIdKeywordErrdefer) ? - ast_parse_payload(pc) : 0; - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeDefer, defer); - - res->data.defer.kind = ReturnKindUnconditional; - res->data.defer.expr = statement; - if (pc->token_ids[defer] == TokenIdKeywordErrdefer) { - res->data.defer.kind = ReturnKindError; - if (payload != 0) - res->data.defer.err_payload = token_identifier(pc, payload); - } - return res; - } - - AstNode *if_statement = ast_parse_if_statement(pc); - if (if_statement != nullptr) - return if_statement; - - AstNode *labeled_statement = ast_parse_labeled_statement(pc); - if (labeled_statement != nullptr) - return labeled_statement; - - AstNode *switch_expr = ast_parse_switch_expr(pc); - if (switch_expr != nullptr) - return switch_expr; - - AstNode *assign = ast_parse_assign_expr(pc); - if (assign != nullptr) { - expect_token(pc, TokenIdSemicolon); - return assign; - } - - return nullptr; -} - -// IfStatement -// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? -// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) -static AstNode *ast_parse_if_statement(ParseContext *pc) { - AstNode *res = ast_parse_if_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected if body, found '%s'", token_name(pc->token_ids[tok])); - } - - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeIfOptional); - if (err_payload != 0) { - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfErrorExpr; - res->data.if_err_expr.target_node = old.target_node; - res->data.if_err_expr.var_is_ptr = old.var_is_ptr; - res->data.if_err_expr.var_symbol = old.var_symbol; - res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); - res->data.if_err_expr.else_node = else_body; - return res; - } - - if (res->data.test_expr.var_symbol != nullptr) { - res->data.test_expr.then_node = body; - res->data.test_expr.else_node = else_body; - return res; - } - - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfBoolExpr; - res->data.if_bool_expr.condition = old.target_node; - res->data.if_bool_expr.then_block = body; - res->data.if_bool_expr.else_node = else_body; - return res; -} - -// LabeledStatement <- BlockLabel? (Block / LoopStatement) -static AstNode *ast_parse_labeled_statement(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - AstNode *block = ast_parse_block(pc); - if (block != nullptr) { - assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(pc, label); - return block; - } - - AstNode *loop = ast_parse_loop_statement(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } - - if (label != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) -static AstNode *ast_parse_loop_statement(ParseContext *pc) { - TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); - AstNode *for_statement = ast_parse_for_statement(pc); - if (for_statement != nullptr) { - assert(for_statement->type == NodeTypeForExpr); - for_statement->data.for_expr.is_inline = inline_token != 0; - return for_statement; - } - - AstNode *while_statement = ast_parse_while_statement(pc); - if (while_statement != nullptr) { - assert(while_statement->type == NodeTypeWhileExpr); - while_statement->data.while_expr.is_inline = inline_token != 0; - return while_statement; - } - - if (inline_token != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// ForStatement -// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? -// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) -static AstNode *ast_parse_for_statement(ParseContext *pc) { - AstNode *res = ast_parse_for_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); - } - - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeForExpr); - res->data.for_expr.body = body; - res->data.for_expr.else_node = else_body; - return res; -} - -// WhileStatement -// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? -// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) -static AstNode *ast_parse_while_statement(ParseContext *pc) { - AstNode *res = ast_parse_while_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); - } - - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeWhileExpr); - res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(pc, err_payload); - res->data.while_expr.else_node = else_body; - return res; -} - - -// BlockExprStatement -// <- BlockExpr -// / AssignExpr SEMICOLON -static AstNode *ast_parse_block_expr_statement(ParseContext *pc) { - AstNode *block = ast_parse_block_expr(pc); - if (block != nullptr) - return block; - - AstNode *assign_expr = ast_parse_assign_expr(pc); - if (assign_expr != nullptr) { - expect_token(pc, TokenIdSemicolon); - return assign_expr; - } - - return nullptr; -} - -// BlockExpr <- BlockLabel? Block -static AstNode *ast_parse_block_expr(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - if (label != 0) { - AstNode *res = ast_expect(pc, ast_parse_block); - assert(res->type == NodeTypeBlock); - res->data.block.name = token_buf(pc, label); - return res; - } - - return ast_parse_block(pc); -} - -// AssignExpr <- Expr (AssignOp Expr)? -static AstNode *ast_parse_assign_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_assign_op, ast_parse_expr); -} - -// Expr <- KEYWORD_try* BoolOrExpr -static AstNode *ast_parse_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - [](ParseContext *context) { - TokenIndex try_token = eat_token_if(context, TokenIdKeywordTry); - if (try_token != 0) { - AstNode *res = ast_create_node(context, NodeTypeReturnExpr, try_token); - res->data.return_expr.kind = ReturnKindError; - return res; - } - - return (AstNode*)nullptr; - }, - ast_parse_bool_or_expr - ); -} - -// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* -static AstNode *ast_parse_bool_or_expr(ParseContext *pc) { - return ast_parse_bin_op_expr( - pc, - BinOpChainInf, - ast_parse_bin_op_simple, - ast_parse_bool_and_expr - ); -} - -// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* -static AstNode *ast_parse_bool_and_expr(ParseContext *pc) { - return ast_parse_bin_op_expr( - pc, - BinOpChainInf, - ast_parse_bin_op_simple, - ast_parse_compare_expr - ); -} - -// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? -static AstNode *ast_parse_compare_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_compare_op, ast_parse_bitwise_expr); -} - -// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* -static AstNode *ast_parse_bitwise_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_bitwise_op, ast_parse_bit_shift_expr); -} - -// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* -static AstNode *ast_parse_bit_shift_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_bit_shift_op, ast_parse_addition_expr); -} - -// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* -static AstNode *ast_parse_addition_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_addition_op, ast_parse_multiply_expr); -} - -// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* -static AstNode *ast_parse_multiply_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_multiply_op, ast_parse_prefix_expr); -} - -// PrefixExpr <- PrefixOp* PrimaryExpr -static AstNode *ast_parse_prefix_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - ast_parse_prefix_op, - ast_parse_primary_expr - ); -} - -// PrimaryExpr -// <- AsmExpr -// / IfExpr -// / KEYWORD_break BreakLabel? Expr? -// / KEYWORD_comptime Expr -// / KEYWORD_nosuspend Expr -// / KEYWORD_continue BreakLabel? -// / KEYWORD_resume Expr -// / KEYWORD_return Expr? -// / BlockLabel? LoopExpr -// / Block -// / CurlySuffixExpr -static AstNode *ast_parse_primary_expr(ParseContext *pc) { - AstNode *asm_expr = ast_parse_asm_expr(pc); - if (asm_expr != nullptr) - return asm_expr; - - AstNode *if_expr = ast_parse_if_expr(pc); - if (if_expr != nullptr) - return if_expr; - - TokenIndex break_token = eat_token_if(pc, TokenIdKeywordBreak); - if (break_token != 0) { - TokenIndex label = ast_parse_break_label(pc); - AstNode *expr = ast_parse_expr(pc); - - AstNode *res = ast_create_node(pc, NodeTypeBreak, break_token); - res->data.break_expr.name = token_buf(pc, label); - res->data.break_expr.expr = expr; - return res; - } - - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = expr; - return res; - } - - TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); - res->data.nosuspend_expr.expr = expr; - return res; - } - - TokenIndex continue_token = eat_token_if(pc, TokenIdKeywordContinue); - if (continue_token != 0) { - TokenIndex label = ast_parse_break_label(pc); - AstNode *res = ast_create_node(pc, NodeTypeContinue, continue_token); - res->data.continue_expr.name = token_buf(pc, label); - return res; - } - - TokenIndex resume = eat_token_if(pc, TokenIdKeywordResume); - if (resume != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeResume, resume); - res->data.resume_expr.expr = expr; - return res; - } - - TokenIndex return_token = eat_token_if(pc, TokenIdKeywordReturn); - if (return_token != 0) { - AstNode *expr = ast_parse_expr(pc); - AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, return_token); - res->data.return_expr.expr = expr; - return res; - } - - TokenIndex label = ast_parse_block_label(pc); - AstNode *loop = ast_parse_loop_expr(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } else if (label != 0) { - // Restore the tokens that we eaten by ast_parse_block_label. - put_back_token(pc); - put_back_token(pc); - } - - AstNode *block = ast_parse_block(pc); - if (block != nullptr) - return block; - - AstNode *curly_suffix = ast_parse_curly_suffix_expr(pc); - if (curly_suffix != nullptr) - return curly_suffix; - - return nullptr; -} - -// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? -static AstNode *ast_parse_if_expr(ParseContext *pc) { - return ast_parse_if_expr_helper(pc, ast_parse_expr); -} - -// Block <- LBRACE Statement* RBRACE -static AstNode *ast_parse_block(ParseContext *pc) { - TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == 0) - return nullptr; - - ZigList statements = {}; - AstNode *statement; - while ((statement = ast_parse_statement(pc)) != nullptr) - statements.append(statement); - - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeBlock, lbrace); - res->data.block.statements = statements; - return res; -} - -// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) -static AstNode *ast_parse_loop_expr(ParseContext *pc) { - return ast_parse_loop_expr_helper( - pc, - ast_parse_for_expr, - ast_parse_while_expr - ); -} - -// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? -static AstNode *ast_parse_for_expr(ParseContext *pc) { - return ast_parse_for_expr_helper(pc, ast_parse_expr); -} - -// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? -static AstNode *ast_parse_while_expr(ParseContext *pc) { - return ast_parse_while_expr_helper(pc, ast_parse_expr); -} - -// CurlySuffixExpr <- TypeExpr InitList? -static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc) { - AstNode *type_expr = ast_parse_type_expr(pc); - if (type_expr == nullptr) - return nullptr; - - AstNode *res = ast_parse_init_list(pc); - if (res == nullptr) - return type_expr; - - assert(res->type == NodeTypeContainerInitExpr); - res->data.container_init_expr.type = type_expr; - return res; -} - -// InitList -// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE -// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE -// / LBRACE RBRACE -static AstNode *ast_parse_init_list(ParseContext *pc) { - TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == 0) - return nullptr; - - AstNode *first = ast_parse_field_init(pc); - if (first != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeContainerInitExpr, lbrace); - res->data.container_init_expr.kind = ContainerInitKindStruct; - res->data.container_init_expr.entries.append(first); - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *field_init = ast_parse_field_init(pc); - if (field_init == nullptr) - break; - res->data.container_init_expr.entries.append(field_init); - } - - expect_token(pc, TokenIdRBrace); - return res; - } - - AstNode *res = ast_create_node(pc, NodeTypeContainerInitExpr, lbrace); - res->data.container_init_expr.kind = ContainerInitKindArray; - - first = ast_parse_expr(pc); - if (first != nullptr) { - res->data.container_init_expr.entries.append(first); - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *expr = ast_parse_expr(pc); - if (expr == nullptr) - break; - res->data.container_init_expr.entries.append(expr); - } - - expect_token(pc, TokenIdRBrace); - return res; - } - - expect_token(pc, TokenIdRBrace); - return res; -} - -// TypeExpr <- PrefixTypeOp* ErrorUnionExpr -static AstNode *ast_parse_type_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - ast_parse_prefix_type_op, - ast_parse_error_union_expr - ); -} - -// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? -static AstNode *ast_parse_error_union_expr(ParseContext *pc) { - AstNode *res = ast_parse_suffix_expr(pc); - if (res == nullptr) - return nullptr; - - AstNode *op = ast_parse_bin_op_simple(pc); - if (op == nullptr) - return res; - - AstNode *right = ast_expect(pc, ast_parse_type_expr); - assert(op->type == NodeTypeBinOpExpr); - op->data.bin_op_expr.op1 = res; - op->data.bin_op_expr.op2 = right; - return op; -} - -// SuffixExpr -// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments -// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* -static AstNode *ast_parse_suffix_expr(ParseContext *pc) { - TokenIndex async_token = eat_token_if(pc, TokenIdKeywordAsync); - if (async_token) { - AstNode *child = ast_expect(pc, ast_parse_primary_type_expr); - while (true) { - AstNode *suffix = ast_parse_suffix_op(pc); - if (suffix == nullptr) - break; - - switch (suffix->type) { - case NodeTypeSliceExpr: - suffix->data.slice_expr.array_ref_expr = child; - break; - case NodeTypeArrayAccessExpr: - suffix->data.array_access_expr.array_ref_expr = child; - break; - case NodeTypeFieldAccessExpr: - suffix->data.field_access_expr.struct_expr = child; - break; - case NodeTypeUnwrapOptional: - suffix->data.unwrap_optional.expr = child; - break; - case NodeTypePtrDeref: - suffix->data.ptr_deref_expr.target = child; - break; - default: - zig_unreachable(); - } - child = suffix; - } - - // TODO: Both *_async_prefix and *_fn_call_arguments returns an - // AstNode *. All we really want here is the arguments of - // the call we parse. We therefor "leak" the node for now. - // Wait till we get async rework to fix this. - AstNode *args = ast_parse_fn_call_arguments(pc); - if (args == nullptr) - ast_invalid_token_error(pc, peek_token(pc)); - - assert(args->type == NodeTypeFnCallExpr); - - AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token); - res->data.fn_call_expr.modifier = CallModifierAsync; - res->data.fn_call_expr.seen = false; - res->data.fn_call_expr.fn_ref_expr = child; - res->data.fn_call_expr.params = args->data.fn_call_expr.params; - return res; - } - - AstNode *res = ast_parse_primary_type_expr(pc); - if (res == nullptr) - return nullptr; - - while (true) { - AstNode *suffix = ast_parse_suffix_op(pc); - if (suffix != nullptr) { - switch (suffix->type) { - case NodeTypeSliceExpr: - suffix->data.slice_expr.array_ref_expr = res; - break; - case NodeTypeArrayAccessExpr: - suffix->data.array_access_expr.array_ref_expr = res; - break; - case NodeTypeFieldAccessExpr: - suffix->data.field_access_expr.struct_expr = res; - break; - case NodeTypeUnwrapOptional: - suffix->data.unwrap_optional.expr = res; - break; - case NodeTypePtrDeref: - suffix->data.ptr_deref_expr.target = res; - break; - default: - zig_unreachable(); - } - res = suffix; - continue; - } - - AstNode * call = ast_parse_fn_call_arguments(pc); - if (call != nullptr) { - assert(call->type == NodeTypeFnCallExpr); - call->data.fn_call_expr.fn_ref_expr = res; - res = call; - continue; - } - - break; - } - - return res; - -} - -// PrimaryTypeExpr -// <- BUILTINIDENTIFIER FnCallArguments -// / CHAR_LITERAL -// / ContainerDecl -// / DOT IDENTIFIER -// / ErrorSetDecl -// / FLOAT -// / FnProto -// / GroupedExpr -// / LabeledTypeExpr -// / IDENTIFIER -// / IfTypeExpr -// / INTEGER -// / KEYWORD_comptime TypeExpr -// / KEYWORD_error DOT IDENTIFIER -// / KEYWORD_promise -// / KEYWORD_unreachable -// / STRINGLITERAL -// / SwitchExpr -static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { - TokenIndex builtin_tok = eat_token_if(pc, TokenIdBuiltin); - if (builtin_tok != 0) { - AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments); - AstNode *name_sym = ast_create_node(pc, NodeTypeIdentifier, builtin_tok); - - assert(res->type == NodeTypeFnCallExpr); - res->main_token = builtin_tok; - res->data.fn_call_expr.fn_ref_expr = name_sym; - res->data.fn_call_expr.modifier = CallModifierBuiltin; - return res; - } - - TokenIndex char_lit = eat_token_if(pc, TokenIdCharLiteral); - if (char_lit != 0) { - return ast_create_node(pc, NodeTypeCharLiteral, char_lit); - } - - AstNode *container_decl = ast_parse_container_decl(pc); - if (container_decl != nullptr) - return container_decl; - - AstNode *anon_lit = ast_parse_anon_lit(pc); - if (anon_lit != nullptr) - return anon_lit; - - AstNode *error_set_decl = ast_parse_error_set_decl(pc); - if (error_set_decl != nullptr) - return error_set_decl; - - TokenIndex float_lit = eat_token_if(pc, TokenIdFloatLiteral); - if (float_lit != 0) { - return ast_create_node(pc, NodeTypeFloatLiteral, float_lit); - } - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) - return fn_proto; - - AstNode *grouped_expr = ast_parse_grouped_expr(pc); - if (grouped_expr != nullptr) - return grouped_expr; - - AstNode *labeled_type_expr = ast_parse_labeled_type_expr(pc); - if (labeled_type_expr != nullptr) - return labeled_type_expr; - - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier != 0) - return token_identifier(pc, identifier); - - AstNode *if_type_expr = ast_parse_if_type_expr(pc); - if (if_type_expr != nullptr) - return if_type_expr; - - TokenIndex int_lit = eat_token_if(pc, TokenIdIntLiteral); - if (int_lit != 0) { - return ast_create_node(pc, NodeTypeIntLiteral, int_lit); - } - - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != 0) { - AstNode *expr = ast_expect(pc, ast_parse_type_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = expr; - return res; - } - - TokenIndex error = eat_token_if(pc, TokenIdKeywordError); - if (error != 0) { - TokenIndex dot = expect_token(pc, TokenIdDot); - TokenIndex name = expect_token(pc, TokenIdIdentifier); - AstNode *left = ast_create_node(pc, NodeTypeErrorType, error); - AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); - res->data.field_access_expr.struct_expr = left; - res->data.field_access_expr.field_name = token_buf(pc, name); - return res; - } - - TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != 0) - return ast_create_node(pc, NodeTypeAnyFrameType, anyframe); - - TokenIndex unreachable = eat_token_if(pc, TokenIdKeywordUnreachable); - if (unreachable != 0) - return ast_create_node(pc, NodeTypeUnreachable, unreachable); - - - TokenIndex string_lit = eat_token_if(pc, TokenIdStringLiteral); - if (string_lit != 0) { - return ast_create_node(pc, NodeTypeStringLiteral, string_lit); - } - - TokenIndex multiline_str_lit = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); - if (multiline_str_lit != 0) { - return ast_create_node(pc, NodeTypeStringLiteral, multiline_str_lit); - } - - AstNode *switch_expr = ast_parse_switch_expr(pc); - if (switch_expr != nullptr) - return switch_expr; - - return nullptr; -} - -// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto -static AstNode *ast_parse_container_decl(ParseContext *pc) { - TokenIndex layout_token = eat_token_if(pc, TokenIdKeywordExtern); - if (layout_token == 0) - layout_token = eat_token_if(pc, TokenIdKeywordPacked); - - AstNode *res = ast_parse_container_decl_auto(pc); - if (res == nullptr) { - if (layout_token != 0) - put_back_token(pc); - return nullptr; - } - - assert(res->type == NodeTypeContainerDecl); - if (layout_token != 0) { - res->main_token = layout_token; - res->data.container_decl.layout = pc->token_ids[layout_token] == TokenIdKeywordExtern - ? ContainerLayoutExtern - : ContainerLayoutPacked; - } - return res; -} - -// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE -static AstNode *ast_parse_error_set_decl(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordError); - if (first == 0) - return nullptr; - if (eat_token_if(pc, TokenIdLBrace) == 0) { - put_back_token(pc); - return nullptr; - } - - ZigList decls = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - TokenIndex doc_token = ast_parse_doc_comments(context); - TokenIndex ident = eat_token_if(context, TokenIdIdentifier); - if (ident == 0) - return (AstNode*)nullptr; - - AstNode *symbol_node = token_identifier(context, ident); - if (doc_token == 0) - return symbol_node; - - AstNode *field_node = ast_create_node(context, NodeTypeErrorSetField, doc_token); - field_node->data.err_set_field.field_name = symbol_node; - field_node->data.err_set_field.doc_comments = doc_token; - return field_node; - }); - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeErrorSetDecl, first); - res->data.err_set_decl.decls = decls; - return res; -} - -// GroupedExpr <- LPAREN Expr RPAREN -static AstNode *ast_parse_grouped_expr(ParseContext *pc) { - TokenIndex lparen = eat_token_if(pc, TokenIdLParen); - if (lparen == 0) - return nullptr; - - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AstNode *res = ast_create_node(pc, NodeTypeGroupedExpr, lparen); - res->data.grouped_expr = expr; - return res; -} - -// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? -static AstNode *ast_parse_if_type_expr(ParseContext *pc) { - return ast_parse_if_expr_helper(pc, ast_parse_type_expr); -} - -// LabeledTypeExpr -// <- BlockLabel Block -// / BlockLabel? LoopTypeExpr -static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - if (label != 0) { - AstNode *block = ast_parse_block(pc); - if (block != nullptr) { - assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(pc, label); - return block; - } - } - - AstNode *loop = ast_parse_loop_type_expr(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } - - if (label != 0) { - put_back_token(pc); - put_back_token(pc); - } - return nullptr; -} - -// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) -static AstNode *ast_parse_loop_type_expr(ParseContext *pc) { - return ast_parse_loop_expr_helper( - pc, - ast_parse_for_type_expr, - ast_parse_while_type_expr - ); -} - -// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? -static AstNode *ast_parse_for_type_expr(ParseContext *pc) { - return ast_parse_for_expr_helper(pc, ast_parse_type_expr); -} - -// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? -static AstNode *ast_parse_while_type_expr(ParseContext *pc) { - return ast_parse_while_expr_helper(pc, ast_parse_type_expr); -} - -// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE -static AstNode *ast_parse_switch_expr(ParseContext *pc) { - TokenIndex switch_token = eat_token_if(pc, TokenIdKeywordSwitch); - if (switch_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - expect_token(pc, TokenIdLBrace); - ZigList prongs = ast_parse_list(pc, TokenIdComma, ast_parse_switch_prong); - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeSwitchExpr, switch_token); - res->data.switch_expr.expr = expr; - res->data.switch_expr.prongs = prongs; - return res; -} - -// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN -static AstNode *ast_parse_asm_expr(ParseContext *pc) { - TokenIndex asm_token = eat_token_if(pc, TokenIdKeywordAsm); - if (asm_token == 0) - return nullptr; - - TokenIndex volatile_token = eat_token_if(pc, TokenIdKeywordVolatile); - expect_token(pc, TokenIdLParen); - AstNode *asm_template = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_parse_asm_output(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - expect_token(pc, TokenIdRParen); - - res->main_token = asm_token; - res->data.asm_expr.volatile_token = volatile_token; - res->data.asm_expr.asm_template = asm_template; - return res; -} - -static AstNode *ast_parse_anon_lit(ParseContext *pc) { - TokenIndex period = eat_token_if(pc, TokenIdDot); - if (period == 0) - return nullptr; - - // anon enum literal - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier != 0) { - return ast_create_node(pc, NodeTypeEnumLiteral, period); - } - - // anon container literal - AstNode *res = ast_parse_init_list(pc); - if (res != nullptr) - return res; - put_back_token(pc); - return nullptr; -} - -// AsmOutput <- COLON AsmOutputList AsmInput? -static AstNode *ast_parse_asm_output(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList output_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_output_item); - AstNode *res = ast_parse_asm_input(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - - res->data.asm_expr.output_list = output_list; - return res; -} - -// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN -static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == 0) - return nullptr; - - TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdRBracket); - - TokenIndex str = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); - if (str == 0) - str = expect_token(pc, TokenIdStringLiteral); - expect_token(pc, TokenIdLParen); - - TokenIndex var_name = eat_token_if(pc, TokenIdIdentifier); - AstNode *return_type = nullptr; - if (var_name == 0) { - expect_token(pc, TokenIdArrow); - return_type = ast_expect(pc, ast_parse_type_expr); - } - - expect_token(pc, TokenIdRParen); - - AsmOutput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(pc, sym_name); - res->constraint = token_buf(pc, str); - res->variable_name = token_buf(pc, var_name); - res->return_type = return_type; - return res; -} - -// AsmInput <- COLON AsmInputList AsmClobbers? -static AstNode *ast_parse_asm_input(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList input_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_input_item); - AstNode *res = ast_parse_asm_clobbers(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - - res->data.asm_expr.input_list = input_list; - return res; -} - -// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN -static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == 0) - return nullptr; - - TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdRBracket); - - TokenIndex constraint = expect_token(pc, TokenIdStringLiteral); - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AsmInput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(pc, sym_name); - res->constraint = token_buf(pc, constraint); - res->expr = expr; - return res; -} - -// AsmClobbers <- COLON StringList -static AstNode *ast_parse_asm_clobbers(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList clobber_list = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - TokenIndex str = eat_token_if(context, TokenIdStringLiteral); - if (str == 0) - str = ast_parse_multi_tok(context, TokenIdMultilineStringLiteralLine); - if (str != 0) - return token_buf(context, str); - return (Buf*)nullptr; - }); - - AstNode *res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - res->data.asm_expr.clobber_list = clobber_list; - return res; -} - -// BreakLabel <- COLON IDENTIFIER -static TokenIndex ast_parse_break_label(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return 0; - - return expect_token(pc, TokenIdIdentifier); -} - -// BlockLabel <- IDENTIFIER COLON -static TokenIndex ast_parse_block_label(ParseContext *pc) { - TokenIndex ident = eat_token_if(pc, TokenIdIdentifier); - if (ident == 0) - return 0; - - // We do 2 token lookahead here, as we don't want to error when - // parsing identifiers. - if (eat_token_if(pc, TokenIdColon) == 0) { - put_back_token(pc); - return 0; - } - - return ident; -} - -// FieldInit <- DOT IDENTIFIER EQUAL Expr -static AstNode *ast_parse_field_init(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdDot); - if (first == 0) - return nullptr; - - TokenIndex name = eat_token_if(pc, TokenIdIdentifier); - if (name == 0) { - // Because of anon literals ".{" is also valid. - put_back_token(pc); - return nullptr; - } - if (eat_token_if(pc, TokenIdEq) == 0) { - // Because ".Name" can also be interpreted as an enum literal, we should put back - // those two tokens again so that the parser can try to parse them as the enum - // literal later. - put_back_token(pc); - put_back_token(pc); - return nullptr; - } - AstNode *expr = ast_expect(pc, ast_parse_expr); - - AstNode *res = ast_create_node(pc, NodeTypeStructValueField, first); - res->data.struct_val_field.name = token_buf(pc, name); - res->data.struct_val_field.expr = expr; - return res; -} - -// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN -static AstNode *ast_parse_while_continue_expr(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdColon); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_assign_expr); - expect_token(pc, TokenIdRParen); - return expr; -} - -// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN -static AstNode *ast_parse_link_section(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordLinkSection); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN -static AstNode *ast_parse_callconv(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordCallconv); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType -static AstNode *ast_parse_param_decl(ParseContext *pc) { - TokenIndex first_doc_comment = ast_parse_doc_comments(pc); - - TokenIndex first = eat_token_if(pc, TokenIdKeywordNoAlias); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordCompTime); - - TokenIndex name = eat_token_if(pc, TokenIdIdentifier); - if (name != 0) { - if (eat_token_if(pc, TokenIdColon) != 0) { - if (first == 0) - first = name; - } else { - // We put back the ident, so it can be parsed as a ParamType - // later. - put_back_token(pc); - name = 0; - } - } - - AstNode *res; - if (first == 0) { - first = peek_token(pc); - res = ast_parse_param_type(pc); - } else { - res = ast_expect(pc, ast_parse_param_type); - } - - if (res == nullptr) - return nullptr; - - assert(res->type == NodeTypeParamDecl); - res->main_token = first; - res->data.param_decl.name = token_buf(pc, name); - res->data.param_decl.doc_comments = first_doc_comment; - res->data.param_decl.is_noalias = pc->token_ids[first] == TokenIdKeywordNoAlias; - res->data.param_decl.is_comptime = pc->token_ids[first] == TokenIdKeywordCompTime; - return res; -} - -// ParamType -// <- KEYWORD_anytype -// / DOT3 -// / TypeExpr -static AstNode *ast_parse_param_type(ParseContext *pc) { - TokenIndex anytype_token = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeParamDecl, anytype_token); - res->data.param_decl.anytype_token = anytype_token; - return res; - } - - TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != 0) { - AstNode *res = ast_create_node(pc, NodeTypeParamDecl, dots); - res->data.param_decl.is_var_args = true; - return res; - } - - AstNode *type_expr = ast_parse_type_expr(pc); - if (type_expr != nullptr) { - AstNode *res = ast_create_node_copy_line_info(pc, NodeTypeParamDecl, type_expr); - res->data.param_decl.type = type_expr; - return res; - } - - return nullptr; -} - -// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? -static AstNode *ast_parse_if_prefix(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordIf); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *condition = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - Optional opt_payload = ast_parse_ptr_payload(pc); - - PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); - res->data.test_expr.target_node = condition; - if (opt_payload.unwrap(&payload)) { - res->data.test_expr.var_symbol = token_buf(pc, payload.payload); - res->data.test_expr.var_is_ptr = payload.asterisk != 0; - } - return res; -} - -// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? -static AstNode *ast_parse_while_prefix(ParseContext *pc) { - TokenIndex while_token = eat_token_if(pc, TokenIdKeywordWhile); - if (while_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *condition = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - Optional opt_payload = ast_parse_ptr_payload(pc); - AstNode *continue_expr = ast_parse_while_continue_expr(pc); - - PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeWhileExpr, while_token); - res->data.while_expr.condition = condition; - res->data.while_expr.continue_expr = continue_expr; - if (opt_payload.unwrap(&payload)) { - res->data.while_expr.var_symbol = token_buf(pc, payload.payload); - res->data.while_expr.var_is_ptr = payload.asterisk != 0; - } - - return res; -} - -// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload -static AstNode *ast_parse_for_prefix(ParseContext *pc) { - TokenIndex for_token = eat_token_if(pc, TokenIdKeywordFor); - if (for_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *array_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - PtrIndexPayload payload; - if (!ast_parse_ptr_index_payload(pc).unwrap(&payload)) - ast_invalid_token_error(pc, peek_token(pc)); - - AstNode *res = ast_create_node(pc, NodeTypeForExpr, for_token); - res->data.for_expr.array_expr = array_expr; - res->data.for_expr.elem_node = token_identifier(pc, payload.payload); - res->data.for_expr.elem_is_ptr = payload.asterisk != 0; - if (payload.index != 0) - res->data.for_expr.index_node = token_identifier(pc, payload.index); - - return res; -} - -// Payload <- PIPE IDENTIFIER PIPE -static TokenIndex ast_parse_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return 0; - - TokenIndex res = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - return res; -} - -// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE -static Optional ast_parse_ptr_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return Optional::none(); - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - TokenIndex payload = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - - PtrPayload res; - res.asterisk = asterisk; - res.payload = payload; - return Optional::some(res); -} - -// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE -static Optional ast_parse_ptr_index_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return Optional::none(); - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - TokenIndex payload = expect_token(pc, TokenIdIdentifier); - TokenIndex index = 0; - if (eat_token_if(pc, TokenIdComma) != 0) - index = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - - PtrIndexPayload res; - res.asterisk = asterisk; - res.payload = payload; - res.index = index; - return Optional::some(res); -} - -// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr -static AstNode *ast_parse_switch_prong(ParseContext *pc) { - AstNode *res = ast_parse_switch_case(pc); - if (res == nullptr) - return nullptr; - - expect_token(pc, TokenIdFatArrow); - Optional opt_payload = ast_parse_ptr_index_payload(pc); - AstNode *expr = ast_expect(pc, ast_parse_assign_expr); - - PtrIndexPayload payload; - assert(res->type == NodeTypeSwitchProng); - res->data.switch_prong.expr = expr; - if (opt_payload.unwrap(&payload)) { - res->data.switch_prong.var_symbol = token_identifier(pc, payload.payload); - res->data.switch_prong.var_is_ptr = payload.asterisk != 0; - } - - return res; -} - -// SwitchCase -// <- SwitchItem (COMMA SwitchItem)* COMMA? -// / KEYWORD_else -static AstNode *ast_parse_switch_case(ParseContext *pc) { - bool is_inline = eat_token_if(pc, TokenIdKeywordInline) != 0; - AstNode *first = ast_parse_switch_item(pc); - if (first != nullptr) { - AstNode *res = ast_create_node_copy_line_info(pc, NodeTypeSwitchProng, first); - res->data.switch_prong.is_inline = is_inline; - res->data.switch_prong.items.append(first); - res->data.switch_prong.any_items_are_range = first->type == NodeTypeSwitchRange; - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *item = ast_parse_switch_item(pc); - if (item == nullptr) - break; - - res->data.switch_prong.items.append(item); - res->data.switch_prong.any_items_are_range |= item->type == NodeTypeSwitchRange; - } - - return res; - } - - TokenIndex else_token = eat_token_if(pc, TokenIdKeywordElse); - if (else_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeSwitchProng, else_token); - res->data.switch_prong.is_inline = is_inline; - return res; - } - - if (is_inline) pc->current_token -= 1; - return nullptr; -} - -// SwitchItem <- Expr (DOT3 Expr)? -static AstNode *ast_parse_switch_item(ParseContext *pc) { - AstNode *expr = ast_parse_expr(pc); - if (expr == nullptr) - return nullptr; - - TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != 0) { - AstNode *expr2 = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeSwitchRange, dots); - res->data.switch_range.start = expr; - res->data.switch_range.end = expr2; - return res; - } - - return expr; -} - -// AssignOp -// <- ASTERISKEQUAL -// / SLASHEQUAL -// / PERCENTEQUAL -// / PLUSEQUAL -// / MINUSEQUAL -// / LARROW2EQUAL -// / LARROW2PIPEEQUAL -// / RARROW2EQUAL -// / AMPERSANDEQUAL -// / CARETEQUAL -// / PIPEEQUAL -// / ASTERISKPERCENTEQUAL -// / PLUSPERCENTEQUAL -// / MINUSPERCENTEQUAL -// / ASTERISKPIPEEQUAL -// / PLUSPIPEEQUAL -// / MINUSPIPEEQUAL -// / EQUAL -static AstNode *ast_parse_assign_op(ParseContext *pc) { - // In C, we have `T arr[N] = {[i] = T{}};` but it doesn't - // seem to work in C++... - BinOpType table[TokenIdCount] = {}; - table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd; - table[TokenIdBitOrEq] = BinOpTypeAssignBitOr; - table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft; - table[TokenIdBitShiftLeftPipeEq] = BinOpTypeAssignBitShiftLeftSat; - table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight; - table[TokenIdBitXorEq] = BinOpTypeAssignBitXor; - table[TokenIdDivEq] = BinOpTypeAssignDiv; - table[TokenIdEq] = BinOpTypeAssign; - table[TokenIdMinusEq] = BinOpTypeAssignMinus; - table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap; - table[TokenIdMinusPipeEq] = BinOpTypeAssignMinusSat; - table[TokenIdModEq] = BinOpTypeAssignMod; - table[TokenIdPlusEq] = BinOpTypeAssignPlus; - table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap; - table[TokenIdPlusPipeEq] = BinOpTypeAssignPlusSat; - table[TokenIdTimesEq] = BinOpTypeAssignTimes; - table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap; - table[TokenIdTimesPipeEq] = BinOpTypeAssignTimesSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; - -} - -// CompareOp -// <- EQUALEQUAL -// / EXCLAMATIONMARKEQUAL -// / LARROW -// / RARROW -// / LARROWEQUAL -// / RARROWEQUAL -static AstNode *ast_parse_compare_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdCmpEq] = BinOpTypeCmpEq; - table[TokenIdCmpNotEq] = BinOpTypeCmpNotEq; - table[TokenIdCmpLessThan] = BinOpTypeCmpLessThan; - table[TokenIdCmpGreaterThan] = BinOpTypeCmpGreaterThan; - table[TokenIdCmpLessOrEq] = BinOpTypeCmpLessOrEq; - table[TokenIdCmpGreaterOrEq] = BinOpTypeCmpGreaterOrEq; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// BitwiseOp -// <- AMPERSAND -// / CARET -// / PIPE -// / KEYWORD_orelse -// / KEYWORD_catch Payload? -static AstNode *ast_parse_bitwise_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdAmpersand] = BinOpTypeBinAnd; - table[TokenIdBinXor] = BinOpTypeBinXor; - table[TokenIdBinOr] = BinOpTypeBinOr; - table[TokenIdKeywordOrElse] = BinOpTypeUnwrapOptional; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - TokenIndex catch_token = eat_token_if(pc, TokenIdKeywordCatch); - if (catch_token != 0) { - TokenIndex payload = ast_parse_payload(pc); - AstNode *res = ast_create_node(pc, NodeTypeCatchExpr, catch_token); - if (payload != 0) - res->data.unwrap_err_expr.symbol = token_identifier(pc, payload); - - return res; - } - - return nullptr; -} - -// BitShiftOp -// <- LARROW2 -// / LARROW2PIPE -// / RARROW2 -static AstNode *ast_parse_bit_shift_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft; - table[TokenIdBitShiftLeftPipe] = BinOpTypeBitShiftLeftSat; - table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// AdditionOp -// <- PLUS -// / MINUS -// / PLUS2 -// / PLUSPERCENT -// / MINUSPERCENT -// / PLUSPIPE -// / MINUSPIPE -static AstNode *ast_parse_addition_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdPlus] = BinOpTypeAdd; - table[TokenIdDash] = BinOpTypeSub; - table[TokenIdPlusPlus] = BinOpTypeArrayCat; - table[TokenIdPlusPercent] = BinOpTypeAddWrap; - table[TokenIdMinusPercent] = BinOpTypeSubWrap; - table[TokenIdPlusPipe] = BinOpTypeAddSat; - table[TokenIdMinusPipe] = BinOpTypeSubSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// MultiplyOp -// <- PIPE2 -// / ASTERISK -// / SLASH -// / PERCENT -// / ASTERISK2 -// / ASTERISKPERCENT -// / ASTERISKPIPE -static AstNode *ast_parse_multiply_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdBarBar] = BinOpTypeMergeErrorSets; - table[TokenIdStar] = BinOpTypeMult; - table[TokenIdSlash] = BinOpTypeDiv; - table[TokenIdPercent] = BinOpTypeMod; - table[TokenIdStarStar] = BinOpTypeArrayMult; - table[TokenIdTimesPercent] = BinOpTypeMultWrap; - table[TokenIdTimesPipe] = BinOpTypeMultSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// PrefixOp -// <- EXCLAMATIONMARK -// / MINUS -// / TILDE -// / MINUSPERCENT -// / AMPERSAND -// / KEYWORD_try -// / KEYWORD_await -static AstNode *ast_parse_prefix_op(ParseContext *pc) { - PrefixOp table[TokenIdCount] = {}; - table[TokenIdBang] = PrefixOpBoolNot; - table[TokenIdDash] = PrefixOpNegation; - table[TokenIdTilde] = PrefixOpBinNot; - table[TokenIdMinusPercent] = PrefixOpNegationWrap; - table[TokenIdAmpersand] = PrefixOpAddrOf; - - PrefixOp op = table[pc->token_ids[pc->current_token]]; - if (op != PrefixOpInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, op_token); - res->data.prefix_op_expr.prefix_op = op; - return res; - } - - TokenIndex try_token = eat_token_if(pc, TokenIdKeywordTry); - if (try_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, try_token); - res->data.return_expr.kind = ReturnKindError; - return res; - } - - TokenIndex await = eat_token_if(pc, TokenIdKeywordAwait); - if (await != 0) { - AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await); - return res; - } - - return nullptr; -} - -// PrefixTypeOp -// <- QUESTIONMARK -// / KEYWORD_anyframe MINUSRARROW -// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)* -// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)* -static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { - TokenIndex questionmark = eat_token_if(pc, TokenIdQuestion); - if (questionmark != 0) { - AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, questionmark); - res->data.prefix_op_expr.prefix_op = PrefixOpOptional; - return res; - } - - TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != 0) { - if (eat_token_if(pc, TokenIdArrow) != 0) { - AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe); - return res; - } - - put_back_token(pc); - } - - TokenIndex arr_init_lbracket = eat_token_if(pc, TokenIdLBracket); - if (arr_init_lbracket != 0) { - TokenIndex underscore = eat_token_if(pc, TokenIdIdentifier); - if (underscore == 0) { - put_back_token(pc); - } else if (!buf_eql_str(token_buf(pc, underscore), "_")) { - put_back_token(pc); - put_back_token(pc); - } else { - AstNode *sentinel = nullptr; - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *node = ast_create_node(pc, NodeTypeInferredArrayType, arr_init_lbracket); - node->data.inferred_array_type.sentinel = sentinel; - return node; - } - } - - - AstNode *ptr = ast_parse_ptr_type_start(pc); - if (ptr != nullptr) { - assert(ptr->type == NodeTypePointerType); - // We might get two pointers from *_ptr_type_start - AstNode *child = ptr->data.pointer_type.op_expr; - if (child == nullptr) - child = ptr; - while (true) { - TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != 0) { - child->data.pointer_type.allow_zero_token = allowzero_token; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordAlign) != 0) { - expect_token(pc, TokenIdLParen); - AstNode *align_expr = ast_expect(pc, ast_parse_expr); - child->data.pointer_type.align_expr = align_expr; - if (eat_token_if(pc, TokenIdColon) != 0) { - TokenIndex bit_offset_start = expect_token(pc, TokenIdIntLiteral); - expect_token(pc, TokenIdColon); - TokenIndex host_int_bytes = expect_token(pc, TokenIdIntLiteral); - child->data.pointer_type.bit_offset_start = bit_offset_start; - child->data.pointer_type.host_int_bytes = host_int_bytes; - } - expect_token(pc, TokenIdRParen); - continue; - } - - if (eat_token_if(pc, TokenIdKeywordConst) != 0) { - child->data.pointer_type.is_const = true; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { - child->data.pointer_type.is_volatile = true; - continue; - } - - break; - } - - return ptr; - } - - AstNode *array = ast_parse_array_type_start(pc); - if (array != nullptr) { - assert(array->type == NodeTypeArrayType); - while (true) { - TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != 0) { - array->data.array_type.allow_zero_token = allowzero_token; - continue; - } - - AstNode *align_expr = ast_parse_byte_align(pc); - if (align_expr != nullptr) { - array->data.array_type.align_expr = align_expr; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordConst) != 0) { - array->data.array_type.is_const = true; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { - array->data.array_type.is_volatile = true; - continue; - } - break; - } - - return array; - } - - - return nullptr; -} - -// SuffixOp -// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET -// / DOT IDENTIFIER -// / DOTASTERISK -// / DOTQUESTIONMARK -static AstNode *ast_parse_suffix_op(ParseContext *pc) { - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != 0) { - AstNode *start = ast_expect(pc, ast_parse_expr); - AstNode *end = nullptr; - if (eat_token_if(pc, TokenIdEllipsis2) != 0) { - AstNode *sentinel = nullptr; - end = ast_parse_expr(pc); - if (eat_token_if(pc, TokenIdColon) != 0) { - sentinel = ast_parse_expr(pc); - } - expect_token(pc, TokenIdRBracket); - - AstNode *res = ast_create_node(pc, NodeTypeSliceExpr, lbracket); - res->data.slice_expr.start = start; - res->data.slice_expr.end = end; - res->data.slice_expr.sentinel = sentinel; - return res; - } - - expect_token(pc, TokenIdRBracket); - - AstNode *res = ast_create_node(pc, NodeTypeArrayAccessExpr, lbracket); - res->data.array_access_expr.subscript = start; - return res; - } - - TokenIndex dot_asterisk = eat_token_if(pc, TokenIdDotStar); - if (dot_asterisk != 0) - return ast_create_node(pc, NodeTypePtrDeref, dot_asterisk); - - TokenIndex dot = eat_token_if(pc, TokenIdDot); - if (dot != 0) { - if (eat_token_if(pc, TokenIdQuestion) != 0) - return ast_create_node(pc, NodeTypeUnwrapOptional, dot); - - TokenIndex ident = expect_token(pc, TokenIdIdentifier); - AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); - res->data.field_access_expr.field_name = token_buf(pc, ident); - return res; - } - - return nullptr; -} - -// FnCallArguments <- LPAREN ExprList RPAREN -static AstNode *ast_parse_fn_call_arguments(ParseContext *pc) { - TokenIndex paren = eat_token_if(pc, TokenIdLParen); - if (paren == 0) - return nullptr; - - ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren); - res->data.fn_call_expr.params = params; - res->data.fn_call_expr.seen = false; - return res; -} - -// ArrayTypeStart <- LBRACKET Expr? RBRACKET -static AstNode *ast_parse_array_type_start(ParseContext *pc) { - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket == 0) - return nullptr; - - AstNode *size = ast_parse_expr(pc); - AstNode *sentinel = nullptr; - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypeArrayType, lbracket); - res->data.array_type.size = size; - res->data.array_type.sentinel = sentinel; - return res; -} - -// PtrTypeStart -// <- ASTERISK -// / ASTERISK2 -// / PTRUNKNOWN -// / PTRC -static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { - AstNode *sentinel = nullptr; - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - if (asterisk != 0) { - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk); - res->data.pointer_type.star_token = asterisk; - res->data.pointer_type.sentinel = sentinel; - return res; - } - - TokenIndex asterisk2 = eat_token_if(pc, TokenIdStarStar); - if (asterisk2 != 0) { - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk2); - AstNode *res2 = ast_create_node(pc, NodeTypePointerType, asterisk2); - res->data.pointer_type.star_token = asterisk2; - res2->data.pointer_type.star_token = asterisk2; - res2->data.pointer_type.sentinel = sentinel; - res->data.pointer_type.op_expr = res2; - return res; - } - - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != 0) { - TokenIndex star = eat_token_if(pc, TokenIdStar); - if (star == 0) { - put_back_token(pc); - } else { - TokenIndex c_tok = eat_token_if(pc, TokenIdIdentifier); - if (c_tok != 0) { - if (!buf_eql_str(token_buf(pc, c_tok), "c")) { - put_back_token(pc); // c symbol - } else { - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); - res->data.pointer_type.star_token = c_tok; - return res; - } - } - - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); - res->data.pointer_type.star_token = lbracket; - res->data.pointer_type.sentinel = sentinel; - return res; - } - } - - return nullptr; -} - -// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE -static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { - AstNode *res = ast_parse_container_decl_type(pc); - if (res == nullptr) - return nullptr; - - expect_token(pc, TokenIdLBrace); - AstNodeContainerDecl members = ast_parse_container_members(pc); - expect_token(pc, TokenIdRBrace); - - res->data.container_decl.fields = members.fields; - res->data.container_decl.decls = members.decls; - res->data.container_decl.doc_comments = members.doc_comments; - return res; -} - -// ContainerDeclType -// <- KEYWORD_struct (LPAREN Expr RPAREN)? -// / KEYWORD_enum (LPAREN Expr RPAREN)? -// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? -// / KEYWORD_opaque -static AstNode *ast_parse_container_decl_type(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct); - if (first != 0) { - bool explicit_backing_int = false; - if (eat_token_if(pc, TokenIdLParen) != 0) { - explicit_backing_int = true; - ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = nullptr; - res->data.container_decl.kind = ContainerKindStruct; - // We want this to be an error in semantic analysis not parsing to make sharing - // the test suite between stage1 and self hosted easier. - res->data.container_decl.unsupported_explicit_backing_int = explicit_backing_int; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordOpaque); - if (first != 0) { - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = nullptr; - res->data.container_decl.kind = ContainerKindOpaque; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordEnum); - if (first != 0) { - AstNode *init_arg_expr = nullptr; - if (eat_token_if(pc, TokenIdLParen) != 0) { - init_arg_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = init_arg_expr; - res->data.container_decl.kind = ContainerKindEnum; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordUnion); - if (first != 0) { - AstNode *init_arg_expr = nullptr; - bool auto_enum = false; - if (eat_token_if(pc, TokenIdLParen) != 0) { - if (eat_token_if(pc, TokenIdKeywordEnum) != 0) { - auto_enum = true; - if (eat_token_if(pc, TokenIdLParen) != 0) { - init_arg_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - } else { - init_arg_expr = ast_expect(pc, ast_parse_expr); - } - - expect_token(pc, TokenIdRParen); - } - - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = init_arg_expr; - res->data.container_decl.auto_enum = auto_enum; - res->data.container_decl.kind = ContainerKindUnion; - return res; - } - - return nullptr; -} - -// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN -static AstNode *ast_parse_byte_align(ParseContext *pc) { - if (eat_token_if(pc, TokenIdKeywordAlign) == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -static void visit_field(AstNode **node, void (*visit)(AstNode **, void *context), void *context) { - if (*node) { - visit(node, context); - } -} - -static void visit_node_list(ZigList *list, void (*visit)(AstNode **, void *context), void *context) { - if (list) { - for (size_t i = 0; i < list->length; i += 1) { - visit(&list->at(i), context); - } - } -} - -void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context) { - switch (node->type) { - case NodeTypeFnProto: - visit_field(&node->data.fn_proto.return_type, visit, context); - visit_node_list(&node->data.fn_proto.params, visit, context); - visit_field(&node->data.fn_proto.align_expr, visit, context); - visit_field(&node->data.fn_proto.section_expr, visit, context); - break; - case NodeTypeFnDef: - visit_field(&node->data.fn_def.fn_proto, visit, context); - visit_field(&node->data.fn_def.body, visit, context); - break; - case NodeTypeParamDecl: - visit_field(&node->data.param_decl.type, visit, context); - break; - case NodeTypeBlock: - visit_node_list(&node->data.block.statements, visit, context); - break; - case NodeTypeGroupedExpr: - visit_field(&node->data.grouped_expr, visit, context); - break; - case NodeTypeReturnExpr: - visit_field(&node->data.return_expr.expr, visit, context); - break; - case NodeTypeDefer: - visit_field(&node->data.defer.expr, visit, context); - visit_field(&node->data.defer.err_payload, visit, context); - break; - case NodeTypeVariableDeclaration: - visit_field(&node->data.variable_declaration.type, visit, context); - visit_field(&node->data.variable_declaration.expr, visit, context); - visit_field(&node->data.variable_declaration.align_expr, visit, context); - visit_field(&node->data.variable_declaration.section_expr, visit, context); - break; - case NodeTypeTestDecl: - visit_field(&node->data.test_decl.body, visit, context); - break; - case NodeTypeBinOpExpr: - visit_field(&node->data.bin_op_expr.op1, visit, context); - visit_field(&node->data.bin_op_expr.op2, visit, context); - break; - case NodeTypeCatchExpr: - visit_field(&node->data.unwrap_err_expr.op1, visit, context); - visit_field(&node->data.unwrap_err_expr.symbol, visit, context); - visit_field(&node->data.unwrap_err_expr.op2, visit, context); - break; - case NodeTypeIntLiteral: - // none - break; - case NodeTypeFloatLiteral: - // none - break; - case NodeTypeStringLiteral: - // none - break; - case NodeTypeCharLiteral: - // none - break; - case NodeTypeIdentifier: - // none - break; - case NodeTypePrefixOpExpr: - visit_field(&node->data.prefix_op_expr.primary_expr, visit, context); - break; - case NodeTypeFnCallExpr: - visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context); - visit_node_list(&node->data.fn_call_expr.params, visit, context); - break; - case NodeTypeArrayAccessExpr: - visit_field(&node->data.array_access_expr.array_ref_expr, visit, context); - visit_field(&node->data.array_access_expr.subscript, visit, context); - break; - case NodeTypeSliceExpr: - visit_field(&node->data.slice_expr.array_ref_expr, visit, context); - visit_field(&node->data.slice_expr.start, visit, context); - visit_field(&node->data.slice_expr.end, visit, context); - visit_field(&node->data.slice_expr.sentinel, visit, context); - break; - case NodeTypeFieldAccessExpr: - visit_field(&node->data.field_access_expr.struct_expr, visit, context); - break; - case NodeTypePtrDeref: - visit_field(&node->data.ptr_deref_expr.target, visit, context); - break; - case NodeTypeUnwrapOptional: - visit_field(&node->data.unwrap_optional.expr, visit, context); - break; - case NodeTypeUsingNamespace: - visit_field(&node->data.using_namespace.expr, visit, context); - break; - case NodeTypeIfBoolExpr: - visit_field(&node->data.if_bool_expr.condition, visit, context); - visit_field(&node->data.if_bool_expr.then_block, visit, context); - visit_field(&node->data.if_bool_expr.else_node, visit, context); - break; - case NodeTypeIfErrorExpr: - visit_field(&node->data.if_err_expr.target_node, visit, context); - visit_field(&node->data.if_err_expr.then_node, visit, context); - visit_field(&node->data.if_err_expr.else_node, visit, context); - break; - case NodeTypeIfOptional: - visit_field(&node->data.test_expr.target_node, visit, context); - visit_field(&node->data.test_expr.then_node, visit, context); - visit_field(&node->data.test_expr.else_node, visit, context); - break; - case NodeTypeWhileExpr: - visit_field(&node->data.while_expr.condition, visit, context); - visit_field(&node->data.while_expr.body, visit, context); - break; - case NodeTypeForExpr: - visit_field(&node->data.for_expr.elem_node, visit, context); - visit_field(&node->data.for_expr.array_expr, visit, context); - visit_field(&node->data.for_expr.index_node, visit, context); - visit_field(&node->data.for_expr.body, visit, context); - break; - case NodeTypeSwitchExpr: - visit_field(&node->data.switch_expr.expr, visit, context); - visit_node_list(&node->data.switch_expr.prongs, visit, context); - break; - case NodeTypeSwitchProng: - visit_node_list(&node->data.switch_prong.items, visit, context); - visit_field(&node->data.switch_prong.var_symbol, visit, context); - visit_field(&node->data.switch_prong.expr, visit, context); - break; - case NodeTypeSwitchRange: - visit_field(&node->data.switch_range.start, visit, context); - visit_field(&node->data.switch_range.end, visit, context); - break; - case NodeTypeCompTime: - visit_field(&node->data.comptime_expr.expr, visit, context); - break; - case NodeTypeNoSuspend: - visit_field(&node->data.comptime_expr.expr, visit, context); - break; - case NodeTypeBreak: - // none - break; - case NodeTypeContinue: - // none - break; - case NodeTypeUnreachable: - // none - break; - case NodeTypeAsmExpr: - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - visit_field(&asm_input->expr, visit, context); - } - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - visit_field(&asm_output->return_type, visit, context); - } - break; - case NodeTypeContainerDecl: - visit_node_list(&node->data.container_decl.fields, visit, context); - visit_node_list(&node->data.container_decl.decls, visit, context); - visit_field(&node->data.container_decl.init_arg_expr, visit, context); - break; - case NodeTypeStructField: - visit_field(&node->data.struct_field.type, visit, context); - visit_field(&node->data.struct_field.value, visit, context); - break; - case NodeTypeContainerInitExpr: - visit_field(&node->data.container_init_expr.type, visit, context); - visit_node_list(&node->data.container_init_expr.entries, visit, context); - break; - case NodeTypeStructValueField: - visit_field(&node->data.struct_val_field.expr, visit, context); - break; - case NodeTypeArrayType: - visit_field(&node->data.array_type.size, visit, context); - visit_field(&node->data.array_type.sentinel, visit, context); - visit_field(&node->data.array_type.child_type, visit, context); - visit_field(&node->data.array_type.align_expr, visit, context); - break; - case NodeTypeInferredArrayType: - visit_field(&node->data.array_type.sentinel, visit, context); - visit_field(&node->data.array_type.child_type, visit, context); - break; - case NodeTypeAnyFrameType: - visit_field(&node->data.anyframe_type.payload_type, visit, context); - break; - case NodeTypeErrorType: - // none - break; - case NodeTypePointerType: - visit_field(&node->data.pointer_type.sentinel, visit, context); - visit_field(&node->data.pointer_type.align_expr, visit, context); - visit_field(&node->data.pointer_type.op_expr, visit, context); - break; - case NodeTypeErrorSetDecl: - visit_node_list(&node->data.err_set_decl.decls, visit, context); - break; - case NodeTypeErrorSetField: - visit_field(&node->data.err_set_field.field_name, visit, context); - break; - case NodeTypeResume: - visit_field(&node->data.resume_expr.expr, visit, context); - break; - case NodeTypeAwaitExpr: - visit_field(&node->data.await_expr.expr, visit, context); - break; - case NodeTypeSuspend: - visit_field(&node->data.suspend.block, visit, context); - break; - case NodeTypeEnumLiteral: - case NodeTypeAnyTypeField: - break; - } -} - -Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index) { - size_t byte_offset = 0; - - assert(source[byte_offset] == '"'); - byte_offset += 1; - - buf_resize(out, 0); - - uint32_t codepoint; - - enum { - StateStart, - StateBackslash, - StateUnicodeLBrace, - StateUnicodeDigit, - } state = StateStart; - for (;;byte_offset += 1) { - switch (state) { - case StateStart: switch (source[byte_offset]) { - case '\\': - state = StateBackslash; - continue; - case '\n': - *bad_index = byte_offset; - return ErrorInvalidCharacter; - case '"': - return ErrorNone; - default: - buf_append_char(out, source[byte_offset]); - continue; - } - case StateBackslash: switch (source[byte_offset]) { - case 'n': - buf_append_char(out, '\n'); - state = StateStart; - continue; - case 'r': - buf_append_char(out, '\r'); - state = StateStart; - continue; - case '\\': - buf_append_char(out, '\\'); - state = StateStart; - continue; - case 't': - buf_append_char(out, '\t'); - state = StateStart; - continue; - case '\'': - buf_append_char(out, '\''); - state = StateStart; - continue; - case '"': - buf_append_char(out, '"'); - state = StateStart; - continue; - case 'x': { - byte_offset += 1; - uint8_t digit1; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit1 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit1 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit1 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - byte_offset += 1; - uint8_t digit0; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit0 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit0 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit0 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - buf_append_char(out, digit1 * 16 + digit0); - state = StateStart; - continue; - } - case 'u': - state = StateUnicodeLBrace; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeLBrace: switch (source[byte_offset]) { - case '{': - state = StateUnicodeDigit; - codepoint = 0; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeDigit: { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '}') { - if (codepoint < 0x80) { - buf_append_char(out, codepoint); - } else if (codepoint < 0x800) { - buf_append_char(out, 0xc0 | (codepoint >> 6)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else if (codepoint < 0x10000) { - buf_append_char(out, 0xe0 | (codepoint >> 12)); - buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else if (codepoint < 0x110000) { - buf_append_char(out, 0xf0 | (codepoint >> 18)); - buf_append_char(out, 0x80 | ((codepoint >> 12) & 0x3f)); - buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else { - *bad_index = byte_offset; - return ErrorUnicodePointTooLarge; - } - state = StateStart; - continue; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - codepoint = codepoint * 16 + digit; - continue; - } - } - } - zig_unreachable(); -} - -static uint32_t utf8_code_point(const uint8_t *bytes) { - if (bytes[0] <= 0x7f) { - return bytes[0]; - } else if (bytes[0] >= 0xc0 && bytes[0] <= 0xdf) { - uint32_t result = bytes[0] & 0x1f; - result <<= 6; - result |= bytes[1] & 0x3f; - return result; - } else if (bytes[0] >= 0xe0 && bytes[0] <= 0xef) { - uint32_t result = bytes[0] & 0xf; - - result <<= 6; - result |= bytes[1] & 0x3f; - - result <<= 6; - result |= bytes[2] & 0x3f; - - return result; - } else if (bytes[0] >= 0xf0 && bytes[0] <= 0xf7) { - uint32_t result = bytes[0] & 0x7; - - result <<= 6; - result |= bytes[1] & 0x3f; - - result <<= 6; - result |= bytes[2] & 0x3f; - - result <<= 6; - result |= bytes[3] & 0x3f; - - return result; - } else { - zig_unreachable(); - } -} - -Error source_char_literal(const char *source, uint32_t *result, size_t *bad_index) { - if (source[0] != '\\') { - *result = utf8_code_point((const uint8_t *)source); - return ErrorNone; - } - - uint32_t byte_offset = 1; - uint32_t codepoint; - - enum State { - StateBackslash, - StateUnicodeLBrace, - StateUnicodeDigit, - } state = StateBackslash; - - for (;;byte_offset += 1) { - switch (state) { - case StateBackslash: switch (source[byte_offset]) { - case 'n': - *result = '\n'; - return ErrorNone; - case 'r': - *result = '\r'; - return ErrorNone; - case '\\': - *result = '\\'; - return ErrorNone; - case 't': - *result = '\t'; - return ErrorNone; - case '\'': - *result = '\''; - return ErrorNone; - case '"': - *result = '"'; - return ErrorNone; - case 'x': { - byte_offset += 1; - uint8_t digit1; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit1 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit1 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit1 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - byte_offset += 1; - uint8_t digit0; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit0 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit0 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit0 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - *result = digit1 * 16 + digit0; - return ErrorNone; - } - case 'u': - state = StateUnicodeLBrace; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeLBrace: switch (source[byte_offset]) { - case '{': - state = StateUnicodeDigit; - codepoint = 0; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeDigit: { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '}') { - if (codepoint < 0x110000) { - *result = codepoint; - return ErrorNone; - } else { - *bad_index = byte_offset; - return ErrorUnicodePointTooLarge; - } - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - codepoint = codepoint * 16 + digit; - continue; - } - } - } -} - -static Buf *token_identifier_buf2(RootStruct *root_struct, TokenIndex token, bool *is_at_syntax) { - Error err; - const char *source = buf_ptr(root_struct->source_code); - size_t byte_offset = root_struct->token_locs[token].offset; - if (root_struct->token_ids[token] == TokenIdBuiltin) { - byte_offset += 1; - } else { - assert(root_struct->token_ids[token] == TokenIdIdentifier); - } - assert(source[byte_offset] != '.'); // wrong token index - - if (source[byte_offset] == '@') { - *is_at_syntax = true; - size_t bad_index; - Buf *str = buf_alloc(); - if ((err = source_string_literal_buf(source + byte_offset + 1, str, &bad_index))) { - ast_error_offset(root_struct, ErrColorAuto, token, bad_index + 1, - buf_create_from_str("invalid string literal character")); - } - return str; - } else { - *is_at_syntax = false; - size_t start = byte_offset; - for (;; byte_offset += 1) { - if (source[byte_offset] == 0) break; - if ((source[byte_offset] >= 'a' && source[byte_offset] <= 'z') || - (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') || - (source[byte_offset] >= '0' && source[byte_offset] <= '9') || - source[byte_offset] == '_') - { - continue; - } - break; - } - return buf_create_from_mem(source + start, byte_offset - start); - } -} - -Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { - bool trash; - return token_identifier_buf2(root_struct, token, &trash); -} - -Buf *node_identifier_buf(AstNode *node) { - bool trash; - return node_identifier_buf2(node, &trash); -} - -Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax) { - assert(node->type == NodeTypeIdentifier); - // Currently, stage1 runs astgen for every comptime function call, - // resulting the allocation here wasting memory. As a workaround until - // the code is adjusted to make astgen run only once per source node, - // we memoize the result into the AST here. - if (node->data.identifier.name == nullptr) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - node->data.identifier.name = token_identifier_buf2(root_struct, node->main_token, - &node->data.identifier.is_at_syntax); - } - *is_at_syntax = node->data.identifier.is_at_syntax; - return node->data.identifier.name; -} - -void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token) { - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[token].offset; - - bigint_init_unsigned(result, 0); - BigInt radix_bi; - - if (source[byte_offset] == '0') { - byte_offset += 1; - switch (source[byte_offset]) { - case 'b': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 2); - break; - case 'o': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 8); - break; - case 'x': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 16); - break; - default: - bigint_init_unsigned(&radix_bi, 10); - break; - } - } else { - bigint_init_unsigned(&radix_bi, 10); - } - - BigInt digit_value_bi = {}; - BigInt multiplied = {}; - - for (;source[byte_offset] != 0; byte_offset += 1) { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '_') { - continue; - } else { - break; - } - bigint_deinit(&digit_value_bi); - bigint_init_unsigned(&digit_value_bi, digit); - - bigint_deinit(&multiplied); - bigint_mul(&multiplied, result, &radix_bi); - - bigint_add(result, &multiplied, &digit_value_bi); - } - - bigint_deinit(&digit_value_bi); - bigint_deinit(&multiplied); - bigint_deinit(&radix_bi); -} - diff --git a/src/stage1/parser.hpp b/src/stage1/parser.hpp deleted file mode 100644 index 065f951e91f6..000000000000 --- a/src/stage1/parser.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_PARSER_HPP -#define ZIG_PARSER_HPP - -#include "all_types.hpp" -#include "tokenizer.hpp" -#include "errmsg.hpp" - -AstNode * ast_parse(Buf *buf, ZigType *owner, ErrColor err_color); - -void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); - -Buf *node_identifier_buf(AstNode *node); -Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax); - -Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token); - -void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token); - -Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index); -Error source_char_literal(const char *source, uint32_t *out, size_t *bad_index); - -#endif diff --git a/src/stage1/range_set.cpp b/src/stage1/range_set.cpp deleted file mode 100644 index 9e621d2f1305..000000000000 --- a/src/stage1/range_set.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "range_set.hpp" - -AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node) { - for (size_t i = 0; i < rs->src_range_list.length; i += 1) { - RangeWithSrc *range_with_src = &rs->src_range_list.at(i); - Range *range = &range_with_src->range; - if ((bigint_cmp(first, &range->first) == CmpLT && bigint_cmp(last, &range->first) == CmpLT) || - (bigint_cmp(first, &range->last) == CmpGT && bigint_cmp(last, &range->last) == CmpGT)) - { - // first...last is completely before/after `range` - } - else - { - return range_with_src->source_node; - } - } - rs->src_range_list.append({{*first, *last}, source_node}); - - return nullptr; - -} - -static int compare_rangeset(const void *a, const void *b) { - const Range *r1 = &static_cast(a)->range; - const Range *r2 = &static_cast(b)->range; - // Assume no two ranges overlap - switch (bigint_cmp(&r1->first, &r2->first)) { - case CmpLT: return -1; - case CmpGT: return 1; - case CmpEQ: return 0; - } - zig_unreachable(); -} - -void rangeset_sort(RangeSet *rs) { - if (rs->src_range_list.length > 1) { - qsort(rs->src_range_list.items, rs->src_range_list.length, - sizeof(RangeWithSrc), compare_rangeset); - } -} - -bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) { - if (rs->src_range_list.length == 0) - return false; - - rangeset_sort(rs); - - const Range *first_range = &rs->src_range_list.at(0).range; - if (bigint_cmp(&first_range->first, first) != CmpEQ) - return false; - - const Range *last_range = &rs->src_range_list.last().range; - if (bigint_cmp(&last_range->last, last) != CmpEQ) - return false; - - BigInt one; - bigint_init_unsigned(&one, 1); - - // Make sure there are no holes in the first...last range - for (size_t i = 1; i < rs->src_range_list.length; i++) { - const Range *range = &rs->src_range_list.at(i).range; - const Range *prev_range = &rs->src_range_list.at(i - 1).range; - - assert(bigint_cmp(&prev_range->last, &range->first) == CmpLT); - - BigInt last_plus_one; - bigint_add(&last_plus_one, &prev_range->last, &one); - - if (bigint_cmp(&last_plus_one, &range->first) != CmpEQ) - return false; - } - - return true; -} diff --git a/src/stage1/range_set.hpp b/src/stage1/range_set.hpp deleted file mode 100644 index 9164a8b5c0a5..000000000000 --- a/src/stage1/range_set.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_RANGE_SET_HPP -#define ZIG_RANGE_SET_HPP - -#include "all_types.hpp" - -struct Range { - BigInt first; - BigInt last; -}; - -struct RangeWithSrc { - Range range; - AstNode *source_node; -}; - -struct RangeSet { - ZigList src_range_list; -}; - -AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node); -bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last); - -#endif diff --git a/src/stage1/softfloat.hpp b/src/stage1/softfloat.hpp deleted file mode 100644 index b9d886d311d5..000000000000 --- a/src/stage1/softfloat.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_SOFTFLOAT_HPP -#define ZIG_SOFTFLOAT_HPP - -extern "C" { -#include "softfloat.h" -} - -#include "zigendian.h" - -static inline float16_t zig_double_to_f16(double x) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - return f64_to_f16(y); -} - -static inline void zig_double_to_extF80M(double x, extFloat80_t *result) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - f64_to_extF80M(y, result); -} - -static inline void zig_double_to_f128M(double x, float128_t *result) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - f64_to_f128M(y, result); -} - - -// Return value is safe to coerce to float even when |x| is NaN or Infinity. -static inline double zig_f16_to_double(float16_t x) { - float64_t y = f16_to_f64(x); - double z; - static_assert(sizeof(y) == sizeof(z), ""); - memcpy(&z, &y, sizeof(y)); - return z; -} - -static inline bool zig_f16_isNaN(float16_t a) { - union { uint16_t ui; float16_t f; } uA; - uA.f = a; - return 0x7C00 < (uA.ui & 0x7FFF); -} - -static inline bool zig_f128_isNaN(float128_t *aPtr) { - uint64_t hi, lo; - - #if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - hi = aPtr->v[1]; - lo = aPtr->v[0]; - #elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - hi = aPtr->v[0]; - lo = aPtr->v[1]; - #else - #error Unsupported endian - #endif - - uint64_t absA64 = hi & UINT64_C(0x7FFFFFFFFFFFFFFF); - return - (UINT64_C(0x7FFF000000000000) < absA64) - || ((absA64 == UINT64_C(0x7FFF000000000000)) && lo); -} - -static inline bool zig_extF80_isNaN(extFloat80_t *aPtr) { - return (aPtr->signExp & 0x7FFF) == 0x7FFF && aPtr->signif & UINT64_C(0x7FFFFFFFFFFFFFFF); -} - -#endif diff --git a/src/stage1/softfloat_ext.cpp b/src/stage1/softfloat_ext.cpp deleted file mode 100644 index bb4c134d9ec7..000000000000 --- a/src/stage1/softfloat_ext.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "softfloat_ext.hpp" -#include "zigendian.h" - -extern "C" { - #include "softfloat.h" -} - -void f128M_abs(const float128_t *aPtr, float128_t *zPtr) { - // Clear the sign bit. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - zPtr->v[1] = aPtr->v[1] & ~(UINT64_C(1) << 63); - zPtr->v[0] = aPtr->v[0]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - zPtr->v[0] = aPtr->v[0] & ~(UINT64_C(1) << 63); - zPtr->v[1] = aPtr->v[1]; -#else -#error Unsupported endian -#endif -} - -void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(aPtr, &zero_float)) { - f128M_roundToInt(aPtr, softfloat_round_max, false, zPtr); - } else { - f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr); - } -} - -void f128M_neg(const float128_t *aPtr, float128_t *zPtr) { - // Toggle the sign bit. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - zPtr->v[1] = aPtr->v[1] ^ (UINT64_C(1) << 63); - zPtr->v[0] = aPtr->v[0]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - zPtr->v[0] = aPtr->v[0] ^ (UINT64_C(1) << 63); - zPtr->v[1] = aPtr->v[1]; -#else -#error Unsupported endian -#endif -} - -void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - // Clear the sign bit. - zPtr->signExp = aPtr->signExp & UINT16_C(0x7FFF); - zPtr->signif = aPtr->signif; -} - -void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - extFloat80_t zero_float; - ui32_to_extF80M(0, &zero_float); - if (extF80M_lt(aPtr, &zero_float)) { - extF80M_roundToInt(aPtr, softfloat_round_max, false, zPtr); - } else { - extF80M_roundToInt(aPtr, softfloat_round_min, false, zPtr); - } -} - -void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - // Toggle the sign bit. - zPtr->signExp = aPtr->signExp ^ UINT16_C(0x8000); - zPtr->signif = aPtr->signif; -} - -float16_t f16_neg(const float16_t a) { - union { uint16_t ui; float16_t f; } uA; - // Toggle the sign bit. - uA.ui = a.v ^ (UINT16_C(1) << 15); - return uA.f; -} diff --git a/src/stage1/softfloat_ext.hpp b/src/stage1/softfloat_ext.hpp deleted file mode 100644 index 4e6fd753c892..000000000000 --- a/src/stage1/softfloat_ext.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ZIG_SOFTFLOAT_EXT_HPP -#define ZIG_SOFTFLOAT_EXT_HPP - -#include "softfloat_types.h" - -void f128M_abs(const float128_t *aPtr, float128_t *zPtr); -void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); -void f128M_neg(const float128_t *aPtr, float128_t *zPtr); - -void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr); -void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr); -void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr); - -float16_t f16_neg(const float16_t a); - -#endif \ No newline at end of file diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp deleted file mode 100644 index 860d4ba4b143..000000000000 --- a/src/stage1/stage1.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "stage1.h" -#include "os.hpp" -#include "all_types.hpp" -#include "codegen.hpp" - -void zig_stage1_os_init(void) { - os_init(); - mem::init(); - init_all_targets(); -} - -struct ZigStage1 *zig_stage1_create(BuildMode optimize_mode, - const char *main_pkg_path_ptr, size_t main_pkg_path_len, - const char *root_src_path_ptr, size_t root_src_path_len, - const char *zig_lib_dir_ptr, size_t zig_lib_dir_len, - const ZigTarget *target, bool is_test_build) -{ - Buf *main_pkg_path = (main_pkg_path_len == 0) ? - nullptr : buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len); - Buf *root_src_path = buf_create_from_mem(root_src_path_ptr, root_src_path_len); - Buf *zig_lib_dir = buf_create_from_mem(zig_lib_dir_ptr, zig_lib_dir_len); - CodeGen *g = codegen_create(main_pkg_path, root_src_path, target, optimize_mode, - zig_lib_dir, is_test_build); - return &g->stage1; -} - -void zig_stage1_destroy(struct ZigStage1 *stage1) { - CodeGen *codegen = reinterpret_cast(stage1); - codegen_destroy(codegen); -} - -static void add_package(CodeGen *g, ZigStage1Pkg *stage1_pkg, ZigPackage *pkg) { - for (size_t i = 0; i < stage1_pkg->children_len; i += 1) { - ZigStage1Pkg *child_cli_pkg = stage1_pkg->children_ptr[i]; - - Buf *dirname = buf_alloc(); - Buf *basename = buf_alloc(); - os_path_split(buf_create_from_mem(child_cli_pkg->path_ptr, child_cli_pkg->path_len), dirname, basename); - - ZigPackage *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename), - buf_ptr(buf_sprintf("%s.%.*s", buf_ptr(&pkg->pkg_path), - (int)child_cli_pkg->name_len, child_cli_pkg->name_ptr))); - auto entry = pkg->package_table.put_unique( - buf_create_from_mem(child_cli_pkg->name_ptr, child_cli_pkg->name_len), - child_pkg); - if (entry) { - ZigPackage *existing_pkg = entry->value; - Buf *full_path = buf_alloc(); - os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path); - fprintf(stderr, "Unable to add package '%.*s'->'%.*s': already exists as '%s'\n", - (int)child_cli_pkg->name_len, child_cli_pkg->name_ptr, - (int)child_cli_pkg->path_len, child_cli_pkg->path_ptr, - buf_ptr(full_path)); - exit(EXIT_FAILURE); - } - - add_package(g, child_cli_pkg, child_pkg); - } -} - -void zig_stage1_build_object(struct ZigStage1 *stage1) { - CodeGen *g = reinterpret_cast(stage1); - - g->root_out_name = buf_create_from_mem(stage1->root_name_ptr, stage1->root_name_len); - buf_init_from_mem(&g->o_file_output_path, stage1->emit_o_ptr, stage1->emit_o_len); - buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len); - buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len); - buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len); - buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len); - - if (stage1->builtin_zig_path_len != 0) { - g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len); - } - if (stage1->test_filter_len != 0) { - g->test_filter = buf_create_from_mem(stage1->test_filter_ptr, stage1->test_filter_len); - } - if (stage1->test_name_prefix_len != 0) { - g->test_name_prefix = buf_create_from_mem(stage1->test_name_prefix_ptr, stage1->test_name_prefix_len); - } - - g->link_mode_dynamic = stage1->link_mode_dynamic; - g->dll_export_fns = stage1->dll_export_fns; - g->have_pic = stage1->pic; - g->have_pie = stage1->pie; - g->have_lto = stage1->lto; - g->unwind_tables = stage1->unwind_tables; - g->have_stack_probing = stage1->enable_stack_probing; - g->red_zone = stage1->red_zone; - g->omit_frame_pointer = stage1->omit_frame_pointer; - g->is_single_threaded = stage1->is_single_threaded; - g->valgrind_enabled = stage1->valgrind_enabled; - g->tsan_enabled = stage1->tsan_enabled; - g->link_libc = stage1->link_libc; - g->link_libcpp = stage1->link_libcpp; - g->function_sections = stage1->function_sections; - g->include_compiler_rt = stage1->include_compiler_rt; - - g->subsystem = stage1->subsystem; - - g->enable_time_report = stage1->enable_time_report; - g->enable_stack_report = stage1->enable_stack_report; - g->test_is_evented = stage1->test_is_evented; - - g->verbose_ir = stage1->verbose_ir; - g->verbose_llvm_ir = stage1->verbose_llvm_ir; - g->verbose_cimport = stage1->verbose_cimport; - g->verbose_llvm_cpu_features = stage1->verbose_llvm_cpu_features; - - g->err_color = stage1->err_color; - g->code_model = stage1->code_model; - - { - g->strip_debug_symbols = stage1->strip; - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } - } - - g->main_progress_node = stage1->main_progress_node; - - add_package(g, stage1->main_pkg, g->main_pkg); - - codegen_build_object(g); -} diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h deleted file mode 100644 index c8af8b9688b3..000000000000 --- a/src/stage1/stage1.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file deals with exposing stage1 C++ code to stage2 Zig code. - -#ifndef ZIG_STAGE1_H -#define ZIG_STAGE1_H - -#include "zig_llvm.h" - -#include - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -// ABI warning -enum ErrColor { - ErrColorAuto, - ErrColorOff, - ErrColorOn, -}; - -// ABI warning -enum CodeModel { - CodeModelDefault, - CodeModelTiny, - CodeModelSmall, - CodeModelKernel, - CodeModelMedium, - CodeModelLarge, -}; - -// ABI warning -enum TargetSubsystem { - TargetSubsystemConsole, - TargetSubsystemWindows, - TargetSubsystemPosix, - TargetSubsystemNative, - TargetSubsystemEfiApplication, - TargetSubsystemEfiBootServiceDriver, - TargetSubsystemEfiRom, - TargetSubsystemEfiRuntimeDriver, - - // This means Zig should infer the subsystem. - // It's last so that the indexes of other items can line up - // with the enum in builtin.zig. - TargetSubsystemAuto -}; - - -// ABI warning -// Synchronize with std.Target.Os.Tag and target.cpp::os_list -enum Os { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsZOS, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsPS5, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsDriverKit, // Apple DriverKit - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsShaderModel, // DirectX ShaderModel - OsUefi, - OsOpenCL, - OsGLSL450, - OsVulkan, - OsPlan9, - OsOther, -}; - -// ABI warning -struct ZigTarget { - enum ZigLLVM_ArchType arch; - enum Os os; - enum ZigLLVM_EnvironmentType abi; - - bool is_native_os; - bool is_native_cpu; - - const char *llvm_cpu_name; - const char *llvm_cpu_features; - const char *llvm_target_abi; -}; - -// ABI warning -struct Stage2Progress; -// ABI warning -struct Stage2ProgressNode; - -enum BuildMode { - BuildModeDebug, - BuildModeSafeRelease, - BuildModeFastRelease, - BuildModeSmallRelease, -}; - - -struct ZigStage1Pkg { - const char *name_ptr; - size_t name_len; - - const char *path_ptr; - size_t path_len; - - struct ZigStage1Pkg **children_ptr; - size_t children_len; - - struct ZigStage1Pkg *parent; -}; - -// This struct is used by both main.cpp and stage1.zig. -struct ZigStage1 { - const char *root_name_ptr; - size_t root_name_len; - - const char *emit_o_ptr; - size_t emit_o_len; - - const char *emit_h_ptr; - size_t emit_h_len; - - const char *emit_asm_ptr; - size_t emit_asm_len; - - const char *emit_llvm_ir_ptr; - size_t emit_llvm_ir_len; - - const char *emit_bitcode_ptr; - size_t emit_bitcode_len; - - const char *builtin_zig_path_ptr; - size_t builtin_zig_path_len; - - const char *test_filter_ptr; - size_t test_filter_len; - - const char *test_name_prefix_ptr; - size_t test_name_prefix_len; - - void *userdata; - struct ZigStage1Pkg *main_pkg; - struct Stage2ProgressNode *main_progress_node; - - enum CodeModel code_model; - enum TargetSubsystem subsystem; - enum ErrColor err_color; - - bool pic; - bool pie; - bool lto; - bool unwind_tables; - bool link_libc; - bool link_libcpp; - bool strip; - bool is_single_threaded; - bool dll_export_fns; - bool link_mode_dynamic; - bool valgrind_enabled; - bool tsan_enabled; - bool function_sections; - bool include_compiler_rt; - bool enable_stack_probing; - bool red_zone; - bool omit_frame_pointer; - bool enable_time_report; - bool enable_stack_report; - bool test_is_evented; - bool verbose_ir; - bool verbose_llvm_ir; - bool verbose_cimport; - bool verbose_llvm_cpu_features; - - // Set by stage1 - bool have_c_main; - bool have_winmain; - bool have_wwinmain; - bool have_winmain_crt_startup; - bool have_wwinmain_crt_startup; - bool have_dllmain_crt_startup; -}; - -ZIG_EXTERN_C void zig_stage1_os_init(void); - -ZIG_EXTERN_C struct ZigStage1 *zig_stage1_create(enum BuildMode optimize_mode, - const char *main_pkg_path_ptr, size_t main_pkg_path_len, - const char *root_src_path_ptr, size_t root_src_path_len, - const char *zig_lib_dir_ptr, size_t zig_lib_dir_len, - const struct ZigTarget *target, bool is_test_build); - -ZIG_EXTERN_C void zig_stage1_build_object(struct ZigStage1 *); - -ZIG_EXTERN_C void zig_stage1_destroy(struct ZigStage1 *); - -#endif diff --git a/src/stage1/stage2.h b/src/stage1/stage2.h deleted file mode 100644 index 58b3a7687f05..000000000000 --- a/src/stage1/stage2.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2019 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file deals with exposing stage2 Zig code to stage1 C++ code. - -#ifndef ZIG_STAGE2_H -#define ZIG_STAGE2_H - -#include -#include -#include - -#include "stage1.h" - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -#if defined(_MSC_VER) -#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn) -#else -#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn)) -#endif - -// ABI warning: the types and declarations in this file must match both those in -// stage2.cpp and src/stage1.zig. - -// ABI warning -enum Error { - ErrorNone, - ErrorNoMem, - ErrorInvalidFormat, - ErrorSemanticAnalyzeFail, - ErrorAccess, - ErrorInterrupted, - ErrorSystemResources, - ErrorFileNotFound, - ErrorFileSystem, - ErrorFileTooBig, - ErrorDivByZero, - ErrorOverflow, - ErrorPathAlreadyExists, - ErrorUnexpected, - ErrorExactDivRemainder, - ErrorNegativeDenominator, - ErrorShiftedOutOneBits, - ErrorCCompileErrors, - ErrorEndOfFile, - ErrorIsDir, - ErrorNotDir, - ErrorUnsupportedOperatingSystem, - ErrorSharingViolation, - ErrorPipeBusy, - ErrorPrimitiveTypeNotFound, - ErrorCacheUnavailable, - ErrorPathTooLong, - ErrorCCompilerCannotFindFile, - ErrorNoCCompilerInstalled, - ErrorReadingDepFile, - ErrorInvalidDepFile, - ErrorMissingArchitecture, - ErrorMissingOperatingSystem, - ErrorUnknownArchitecture, - ErrorUnknownOperatingSystem, - ErrorUnknownABI, - ErrorInvalidFilename, - ErrorDiskQuota, - ErrorDiskSpace, - ErrorUnexpectedWriteFailure, - ErrorUnexpectedSeekFailure, - ErrorUnexpectedFileTruncationFailure, - ErrorUnimplemented, - ErrorOperationAborted, - ErrorBrokenPipe, - ErrorNoSpaceLeft, - ErrorNotLazy, - ErrorIsAsync, - ErrorImportOutsidePkgPath, - ErrorUnknownCpu, - ErrorUnknownCpuFeature, - ErrorInvalidCpuFeatures, - ErrorInvalidLlvmCpuFeaturesFormat, - ErrorUnknownApplicationBinaryInterface, - ErrorASTUnitFailure, - ErrorBadPathName, - ErrorSymLinkLoop, - ErrorProcessFdQuotaExceeded, - ErrorSystemFdQuotaExceeded, - ErrorNoDevice, - ErrorDeviceBusy, - ErrorUnableToSpawnCCompiler, - ErrorCCompilerExitCode, - ErrorCCompilerCrashed, - ErrorCCompilerCannotFindHeaders, - ErrorLibCRuntimeNotFound, - ErrorLibCStdLibHeaderNotFound, - ErrorLibCKernel32LibNotFound, - ErrorUnsupportedArchitecture, - ErrorWindowsSdkNotFound, - ErrorUnknownDynamicLinkerPath, - ErrorTargetHasNoDynamicLinker, - ErrorInvalidAbiVersion, - ErrorInvalidOperatingSystemVersion, - ErrorUnknownClangOption, - ErrorNestedResponseFile, - ErrorZigIsTheCCompiler, - ErrorFileBusy, - ErrorLocked, - ErrorInvalidCharacter, - ErrorUnicodePointTooLarge, -}; - -// ABI warning -struct Stage2ErrorMsg { - const char *filename_ptr; // can be null - size_t filename_len; - const char *msg_ptr; - size_t msg_len; - const char *source; // valid until the ASTUnit is freed. can be null - unsigned line; // 0 based - unsigned column; // 0 based - unsigned offset; // byte offset into source -}; - -// ABI warning -ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); - -// ABI warning -ZIG_EXTERN_C struct Stage2Progress *stage2_progress_create(void); -// ABI warning -ZIG_EXTERN_C void stage2_progress_disable_tty(struct Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C void stage2_progress_destroy(struct Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start_root(struct Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start(struct Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C void stage2_progress_end(struct Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_complete_one(struct Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_update_node(struct Stage2ProgressNode *node, - size_t completed_count, size_t estimated_total_items); - -// ABI warning -struct Stage2SemVer { - uint32_t major; - uint32_t minor; - uint32_t patch; -}; - -// ABI warning -ZIG_EXTERN_C const char *stage2_version_string(void); - -// ABI warning -ZIG_EXTERN_C Stage2SemVer stage2_version(void); - -// ABI warning -ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu, - const char *dynamic_linker); - -// ABI warning -ZIG_EXTERN_C const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len, - size_t *result_len); - -// ABI warning -ZIG_EXTERN_C Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len, - const char **out_zig_path_ptr, size_t *out_zig_path_len, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len); - -// ABI warning -ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1, - const char *lib_name_ptr, size_t lib_name_len, - const char *symbol_name_ptr, size_t symbol_name_len); - -// ABI warning -ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len); - -#endif diff --git a/src/stage1/target.cpp b/src/stage1/target.cpp deleted file mode 100644 index dfd91bed8aba..000000000000 --- a/src/stage1/target.cpp +++ /dev/null @@ -1,1165 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "buffer.hpp" -#include "error.hpp" -#include "target.hpp" -#include "util.hpp" -#include "os.hpp" - -#include - -static const ZigLLVM_ArchType arch_list[] = { - ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale - ZigLLVM_armeb, // ARM (big endian): armeb - ZigLLVM_aarch64, // AArch64 (little endian): aarch64 - ZigLLVM_aarch64_be, // AArch64 (big endian): aarch64_be - ZigLLVM_aarch64_32, // AArch64 (little endian) ILP32: aarch64_32 - ZigLLVM_arc, // ARC: Synopsys ARC - ZigLLVM_avr, // AVR: Atmel AVR microcontroller - ZigLLVM_bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) - ZigLLVM_bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) - ZigLLVM_csky, // CSKY: csky - ZigLLVM_dxil, // DXIL 32-bit DirectX bytecode - ZigLLVM_hexagon, // Hexagon: hexagon - ZigLLVM_loongarch32, // LoongArch (32-bit): loongarch32 - ZigLLVM_loongarch64, // LoongArch (64-bit): loongarch64 - ZigLLVM_m68k, // M68k: Motorola 680x0 family - ZigLLVM_mips, // MIPS: mips, mipsallegrex, mipsr6 - ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el - ZigLLVM_mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6 - ZigLLVM_mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el - ZigLLVM_msp430, // MSP430: msp430 - ZigLLVM_ppc, // PPC: powerpc - ZigLLVM_ppcle, // PPCLE: powerpc (little endian) - ZigLLVM_ppc64, // PPC64: powerpc64, ppu - ZigLLVM_ppc64le, // PPC64LE: powerpc64le - ZigLLVM_r600, // R600: AMD GPUs HD2XXX - HD6XXX - ZigLLVM_amdgcn, // AMDGCN: AMD GCN GPUs - ZigLLVM_riscv32, // RISC-V (32-bit): riscv32 - ZigLLVM_riscv64, // RISC-V (64-bit): riscv64 - ZigLLVM_sparc, // Sparc: sparc - ZigLLVM_sparcv9, // Sparcv9: Sparcv9 - ZigLLVM_sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant - ZigLLVM_systemz, // SystemZ: s390x - ZigLLVM_tce, // TCE (http://tce.cs.tut.fi/): tce - ZigLLVM_tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele - ZigLLVM_thumb, // Thumb (little endian): thumb, thumbv.* - ZigLLVM_thumbeb, // Thumb (big endian): thumbeb - ZigLLVM_x86, // X86: i[3-9]86 - ZigLLVM_x86_64, // X86-64: amd64, x86_64 - ZigLLVM_xcore, // XCore: xcore - ZigLLVM_nvptx, // NVPTX: 32-bit - ZigLLVM_nvptx64, // NVPTX: 64-bit - ZigLLVM_le32, // le32: generic little-endian 32-bit CPU (PNaCl) - ZigLLVM_le64, // le64: generic little-endian 64-bit CPU (PNaCl) - ZigLLVM_amdil, // AMDIL - ZigLLVM_amdil64, // AMDIL with 64-bit pointers - ZigLLVM_hsail, // AMD HSAIL - ZigLLVM_hsail64, // AMD HSAIL with 64-bit pointers - ZigLLVM_spir, // SPIR: standard portable IR for OpenCL 32-bit version - ZigLLVM_spir64, // SPIR: standard portable IR for OpenCL 64-bit version - ZigLLVM_spirv32, // SPIR-V with 32-bit pointers - ZigLLVM_spirv64, // SPIR-V with 64-bit pointers - ZigLLVM_kalimba, // Kalimba: generic kalimba - ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors - ZigLLVM_lanai, // Lanai: Lanai 32-bit - ZigLLVM_wasm32, // WebAssembly with 32-bit pointers - ZigLLVM_wasm64, // WebAssembly with 64-bit pointers - ZigLLVM_renderscript32, // 32-bit RenderScript - ZigLLVM_renderscript64, // 64-bit RenderScript - ZigLLVM_ve, // NEC SX-Aurora Vector Engine -}; - -static const ZigLLVM_VendorType vendor_list[] = { - ZigLLVM_Apple, - ZigLLVM_PC, - ZigLLVM_SCEI, - ZigLLVM_Freescale, - ZigLLVM_IBM, - ZigLLVM_ImaginationTechnologies, - ZigLLVM_MipsTechnologies, - ZigLLVM_NVIDIA, - ZigLLVM_CSR, - ZigLLVM_Myriad, - ZigLLVM_AMD, - ZigLLVM_Mesa, - ZigLLVM_SUSE, -}; - -static const Os os_list[] = { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsZOS, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsPS5, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsDriverKit, // Apple DriverKit - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsShaderModel, // DirectX ShaderModel - OsUefi, - OsOpenCL, - OsGLSL450, - OsVulkan, - OsPlan9, - OsOther, -}; - -// Coordinate with zig_llvm.h -static const ZigLLVM_EnvironmentType abi_list[] = { - ZigLLVM_UnknownEnvironment, - - ZigLLVM_GNU, - ZigLLVM_GNUABIN32, - ZigLLVM_GNUABI64, - ZigLLVM_GNUEABI, - ZigLLVM_GNUEABIHF, - ZigLLVM_GNUX32, - ZigLLVM_GNUILP32, - ZigLLVM_CODE16, - ZigLLVM_EABI, - ZigLLVM_EABIHF, - ZigLLVM_Android, - ZigLLVM_Musl, - ZigLLVM_MuslEABI, - ZigLLVM_MuslEABIHF, - ZigLLVM_MuslX32, - - ZigLLVM_MSVC, - ZigLLVM_Itanium, - ZigLLVM_Cygnus, - ZigLLVM_CoreCLR, - ZigLLVM_Simulator, // Simulator variants of other systems, e.g., Apple's iOS - ZigLLVM_MacABI, // Mac Catalyst variant of Apple's iOS deployment target. - - ZigLLVM_Pixel, - ZigLLVM_Vertex, - ZigLLVM_Geometry, - ZigLLVM_Hull, - ZigLLVM_Domain, - ZigLLVM_Compute, - ZigLLVM_Library, - ZigLLVM_RayGeneration, - ZigLLVM_Intersection, - ZigLLVM_AnyHit, - ZigLLVM_ClosestHit, - ZigLLVM_Miss, - ZigLLVM_Callable, - ZigLLVM_Mesh, - ZigLLVM_Amplification, -}; - -static const ZigLLVM_ObjectFormatType oformat_list[] = { - ZigLLVM_UnknownObjectFormat, - ZigLLVM_COFF, - ZigLLVM_DXContainer, - ZigLLVM_ELF, - ZigLLVM_GOFF, - ZigLLVM_MachO, - ZigLLVM_SPIRV, - ZigLLVM_Wasm, - ZigLLVM_XCOFF, -}; - -size_t target_oformat_count(void) { - return array_length(oformat_list); -} - -ZigLLVM_ObjectFormatType target_oformat_enum(size_t index) { - assert(index < array_length(oformat_list)); - return oformat_list[index]; -} - -const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat) { - switch (oformat) { - case ZigLLVM_UnknownObjectFormat: return "unknown"; - case ZigLLVM_COFF: return "coff"; - case ZigLLVM_DXContainer: return "dxcontainer"; - case ZigLLVM_ELF: return "elf"; - case ZigLLVM_GOFF: return "goff"; - case ZigLLVM_MachO: return "macho"; - case ZigLLVM_SPIRV: return "spirv"; - case ZigLLVM_Wasm: return "wasm"; - case ZigLLVM_XCOFF: return "xcoff"; - } - zig_unreachable(); -} - -size_t target_arch_count(void) { - return array_length(arch_list); -} - -ZigLLVM_ArchType target_arch_enum(size_t index) { - assert(index < array_length(arch_list)); - return arch_list[index]; -} - -size_t target_vendor_count(void) { - return array_length(vendor_list); -} - -ZigLLVM_VendorType target_vendor_enum(size_t index) { - assert(index < array_length(vendor_list)); - return vendor_list[index]; -} - -size_t target_os_count(void) { - return array_length(os_list); -} -Os target_os_enum(size_t index) { - assert(index < array_length(os_list)); - return os_list[index]; -} - -ZigLLVM_OSType get_llvm_os_type(Os os_type) { - switch (os_type) { - case OsFreestanding: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsPlan9: - case OsOther: - return ZigLLVM_UnknownOS; - case OsAnanas: - return ZigLLVM_Ananas; - case OsCloudABI: - return ZigLLVM_CloudABI; - case OsDragonFly: - return ZigLLVM_DragonFly; - case OsFreeBSD: - return ZigLLVM_FreeBSD; - case OsFuchsia: - return ZigLLVM_Fuchsia; - case OsIOS: - return ZigLLVM_IOS; - case OsKFreeBSD: - return ZigLLVM_KFreeBSD; - case OsLinux: - return ZigLLVM_Linux; - case OsLv2: - return ZigLLVM_Lv2; - case OsMacOSX: - return ZigLLVM_MacOSX; - case OsNetBSD: - return ZigLLVM_NetBSD; - case OsOpenBSD: - return ZigLLVM_OpenBSD; - case OsSolaris: - return ZigLLVM_Solaris; - case OsWindows: - case OsUefi: - return ZigLLVM_Win32; - case OsZOS: - return ZigLLVM_ZOS; - case OsHaiku: - return ZigLLVM_Haiku; - case OsMinix: - return ZigLLVM_Minix; - case OsRTEMS: - return ZigLLVM_RTEMS; - case OsNaCl: - return ZigLLVM_NaCl; - case OsAIX: - return ZigLLVM_AIX; - case OsCUDA: - return ZigLLVM_CUDA; - case OsNVCL: - return ZigLLVM_NVCL; - case OsAMDHSA: - return ZigLLVM_AMDHSA; - case OsPS4: - return ZigLLVM_PS4; - case OsPS5: - return ZigLLVM_PS5; - case OsELFIAMCU: - return ZigLLVM_ELFIAMCU; - case OsTvOS: - return ZigLLVM_TvOS; - case OsWatchOS: - return ZigLLVM_WatchOS; - case OsDriverKit: - return ZigLLVM_DriverKit; - case OsMesa3D: - return ZigLLVM_Mesa3D; - case OsContiki: - return ZigLLVM_Contiki; - case OsAMDPAL: - return ZigLLVM_AMDPAL; - case OsHermitCore: - return ZigLLVM_HermitCore; - case OsHurd: - return ZigLLVM_Hurd; - case OsWASI: - return ZigLLVM_WASI; - case OsEmscripten: - return ZigLLVM_Emscripten; - case OsShaderModel: - return ZigLLVM_ShaderModel; - } - zig_unreachable(); -} - -const char *target_os_name(Os os_type) { - switch (os_type) { - case OsFreestanding: - return "freestanding"; - case OsPlan9: - return "plan9"; - case OsUefi: - return "uefi"; - case OsOther: - return "other"; - case OsAnanas: - case OsCloudABI: - case OsDragonFly: - case OsFreeBSD: - case OsFuchsia: - case OsIOS: - case OsKFreeBSD: - case OsLinux: - case OsLv2: // PS3 - case OsMacOSX: - case OsNetBSD: - case OsOpenBSD: - case OsSolaris: - case OsWindows: - case OsZOS: - case OsHaiku: - case OsMinix: - case OsRTEMS: - case OsNaCl: // Native Client - case OsAIX: - case OsCUDA: // NVIDIA CUDA - case OsNVCL: // NVIDIA OpenCL - case OsAMDHSA: // AMD HSA Runtime - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsTvOS: // Apple tvOS - case OsWatchOS: // Apple watchOS - case OsDriverKit: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsWASI: - case OsEmscripten: - case OsShaderModel: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - return ZigLLVMGetOSTypeName(get_llvm_os_type(os_type)); - } - zig_unreachable(); -} - -size_t target_abi_count(void) { - return array_length(abi_list); -} -ZigLLVM_EnvironmentType target_abi_enum(size_t index) { - assert(index < array_length(abi_list)); - return abi_list[index]; -} -const char *target_abi_name(ZigLLVM_EnvironmentType abi) { - if (abi == ZigLLVM_UnknownEnvironment) - return "none"; - return ZigLLVMGetEnvironmentTypeName(abi); -} - -Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) { - *out_arch = ZigLLVM_UnknownArch; - for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) { - ZigLLVM_ArchType arch = arch_list[arch_i]; - if (mem_eql_str(arch_ptr, arch_len, target_arch_name(arch))) { - *out_arch = arch; - return ErrorNone; - } - } - return ErrorUnknownArchitecture; -} - -Error target_parse_os(Os *out_os, const char *os_ptr, size_t os_len) { - if (mem_eql_str(os_ptr, os_len, "native")) { -#if defined(ZIG_OS_DARWIN) - *out_os = OsMacOSX; - return ErrorNone; -#elif defined(ZIG_OS_WINDOWS) - *out_os = OsWindows; - return ErrorNone; -#elif defined(ZIG_OS_LINUX) - *out_os = OsLinux; - return ErrorNone; -#elif defined(ZIG_OS_FREEBSD) - *out_os = OsFreeBSD; - return ErrorNone; -#elif defined(ZIG_OS_NETBSD) - *out_os = OsNetBSD; - return ErrorNone; -#elif defined(ZIG_OS_DRAGONFLY) - *out_os = OsDragonFly; - return ErrorNone; -#elif defined(ZIG_OS_OPENBSD) - *out_os = OsOpenBSD; - return ErrorNone; -#elif defined(ZIG_OS_HAIKU) - *out_os = OsHaiku; - return ErrorNone; -#elif defined(ZIG_OS_SOLARIS) - *out_os = OsSolaris; - return ErrorNone; -#else - zig_panic("stage1 is unable to detect native target for this OS"); -#endif - } - - for (size_t i = 0; i < array_length(os_list); i += 1) { - Os os = os_list[i]; - const char *os_name = target_os_name(os); - if (mem_eql_str(os_ptr, os_len, os_name)) { - *out_os = os; - return ErrorNone; - } - } - return ErrorUnknownOperatingSystem; -} - -Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, size_t abi_len) { - for (size_t i = 0; i < array_length(abi_list); i += 1) { - ZigLLVM_EnvironmentType abi = abi_list[i]; - const char *abi_name = target_abi_name(abi); - if (mem_eql_str(abi_ptr, abi_len, abi_name)) { - *out_abi = abi; - return ErrorNone; - } - } - return ErrorUnknownABI; -} - -const char *target_arch_name(ZigLLVM_ArchType arch) { - return ZigLLVMGetArchTypeName(arch); -} - -void init_all_targets(void) { - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); -} - -void target_triple_zig(Buf *triple, const ZigTarget *target) { - buf_resize(triple, 0); - buf_appendf(triple, "%s-%s-%s", - target_arch_name(target->arch), - target_os_name(target->os), - target_abi_name(target->abi)); -} - -void target_triple_llvm(Buf *triple, const ZigTarget *target) { - buf_resize(triple, 0); - buf_appendf(triple, "%s-%s-%s-%s", - ZigLLVMGetArchTypeName(target->arch), - ZigLLVMGetVendorTypeName(ZigLLVM_UnknownVendor), - ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)), - ZigLLVMGetEnvironmentTypeName(target->abi)); -} - -bool target_os_is_darwin(Os os) { - switch (os) { - case OsMacOSX: - case OsIOS: - case OsWatchOS: - case OsTvOS: - return true; - default: - return false; - } -} - -ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target) { - if (target->os == OsUefi || target->os == OsWindows) { - return ZigLLVM_COFF; - } else if (target_os_is_darwin(target->os)) { - return ZigLLVM_MachO; - } - if (target->arch == ZigLLVM_wasm32 || - target->arch == ZigLLVM_wasm64) - { - return ZigLLVM_Wasm; - } - return ZigLLVM_ELF; -} - -// See lib/Support/Triple.cpp in LLVM for the source of this data. -// getArchPointerBitWidth -uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - return 0; - - case ZigLLVM_avr: - case ZigLLVM_msp430: - return 16; - - case ZigLLVM_arc: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_le32: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_nvptx: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_r600: - case ZigLLVM_riscv32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_x86: - case ZigLLVM_xcore: - case ZigLLVM_amdil: - case ZigLLVM_hsail: - case ZigLLVM_spir: - case ZigLLVM_kalimba: - case ZigLLVM_lanai: - case ZigLLVM_shave: - case ZigLLVM_wasm32: - case ZigLLVM_renderscript32: - case ZigLLVM_aarch64_32: - case ZigLLVM_csky: - case ZigLLVM_spirv32: - case ZigLLVM_loongarch32: - case ZigLLVM_dxil: - return 32; - - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_amdgcn: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_nvptx64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_riscv64: - case ZigLLVM_sparcv9: - case ZigLLVM_systemz: - case ZigLLVM_x86_64: - case ZigLLVM_amdil64: - case ZigLLVM_hsail64: - case ZigLLVM_spir64: - case ZigLLVM_wasm64: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - case ZigLLVM_spirv64: - case ZigLLVM_loongarch64: - return 64; - } - zig_unreachable(); -} - -uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - - case ZigLLVM_avr: - case ZigLLVM_msp430: - return 16; - - case ZigLLVM_arc: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_le32: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_nvptx: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_r600: - case ZigLLVM_riscv32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_x86: - case ZigLLVM_xcore: - case ZigLLVM_amdil: - case ZigLLVM_hsail: - case ZigLLVM_spir: - case ZigLLVM_kalimba: - case ZigLLVM_lanai: - case ZigLLVM_shave: - case ZigLLVM_wasm32: - case ZigLLVM_renderscript32: - case ZigLLVM_csky: - case ZigLLVM_spirv32: - case ZigLLVM_loongarch32: - case ZigLLVM_dxil: - return 32; - - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_amdgcn: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_nvptx64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_riscv64: - case ZigLLVM_sparcv9: - case ZigLLVM_systemz: - case ZigLLVM_amdil64: - case ZigLLVM_hsail64: - case ZigLLVM_spir64: - case ZigLLVM_wasm64: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - case ZigLLVM_spirv64: - case ZigLLVM_loongarch64: - return 64; - - case ZigLLVM_x86_64: - return 128; - } - zig_unreachable(); -} - -uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { - switch (target->os) { - case OsFreestanding: - case OsOther: - switch (target->arch) { - case ZigLLVM_msp430: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 16; - case CIntTypeLong: - case CIntTypeULong: - return 32; - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - default: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - return target_arch_pointer_bit_width(target->arch); - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - } - zig_unreachable(); - case OsLinux: - case OsMacOSX: - case OsFreeBSD: - case OsNetBSD: - case OsDragonFly: - case OsOpenBSD: - case OsWASI: - case OsHaiku: - case OsSolaris: - case OsEmscripten: - case OsPlan9: - case OsCUDA: - case OsNVCL: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - return target_arch_pointer_bit_width(target->arch); - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsUefi: - case OsWindows: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - case CIntTypeLong: - case CIntTypeULong: - return 32; - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsIOS: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsAnanas: - case OsCloudABI: - case OsKFreeBSD: - case OsLv2: - case OsZOS: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsAIX: - case OsAMDHSA: - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsTvOS: - case OsWatchOS: - case OsMesa3D: - case OsFuchsia: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsDriverKit: - case OsShaderModel: - zig_panic("TODO c type size in bits for this target"); - } - zig_unreachable(); -} - -bool target_allows_addr_zero(const ZigTarget *target) { - return target->os == OsFreestanding || target->os == OsUefi; -} - -const char *target_o_file_ext(const ZigTarget *target) { - if (target->abi == ZigLLVM_MSVC || - target->os == OsWindows || target->os == OsUefi) - { - return ".obj"; - } else { - return ".o"; - } -} - -const char *target_asm_file_ext(const ZigTarget *target) { - return ".s"; -} - -const char *target_llvm_ir_file_ext(const ZigTarget *target) { - return ".ll"; -} - -bool target_is_android(const ZigTarget *target) { - return target->abi == ZigLLVM_Android; -} - -const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86: - return "esp"; - case ZigLLVM_x86_64: - return "rsp"; - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - case ZigLLVM_m68k: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return "sp"; - - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - case ZigLLVM_spirv32: - case ZigLLVM_spirv64: - return nullptr; // known to be not available - - case ZigLLVM_amdgcn: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfeb: - case ZigLLVM_bpfel: - case ZigLLVM_csky: - case ZigLLVM_hexagon: - case ZigLLVM_lanai: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_kalimba: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_msp430: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_r600: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_shave: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_systemz: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_xcore: - case ZigLLVM_ve: - case ZigLLVM_dxil: - case ZigLLVM_loongarch32: - case ZigLLVM_loongarch64: - zig_panic("TODO populate this table with stack pointer register name for this CPU architecture"); - } - zig_unreachable(); -} - -bool target_is_arm(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - return true; - - case ZigLLVM_x86: - case ZigLLVM_x86_64: - case ZigLLVM_amdgcn: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfeb: - case ZigLLVM_bpfel: - case ZigLLVM_csky: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_lanai: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_kalimba: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_mips: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_mipsel: - case ZigLLVM_msp430: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_r600: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - case ZigLLVM_shave: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_systemz: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - case ZigLLVM_xcore: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_ve: - case ZigLLVM_spirv32: - case ZigLLVM_spirv64: - case ZigLLVM_dxil: - case ZigLLVM_loongarch32: - case ZigLLVM_loongarch64: - return false; - } - zig_unreachable(); -} - -// Valgrind supports more, but Zig does not support them yet. -bool target_has_valgrind_support(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86_64: - return (target->os == OsLinux || target->os == OsSolaris || - (target->os == OsWindows && target->abi != ZigLLVM_MSVC)); - default: - return false; - } - zig_unreachable(); -} - -bool target_is_wasm(const ZigTarget *target) { - return target->arch == ZigLLVM_wasm32 || target->arch == ZigLLVM_wasm64; -} - -bool target_is_bpf(const ZigTarget *target) { - return target->arch == ZigLLVM_bpfel || target->arch == ZigLLVM_bpfeb; -} - -ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { - if (arch == ZigLLVM_wasm32 || arch == ZigLLVM_wasm64) { - return ZigLLVM_Musl; - } - switch (os) { - case OsFreestanding: - case OsAnanas: - case OsCloudABI: - case OsLv2: - case OsSolaris: - case OsZOS: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsAIX: - case OsCUDA: - case OsNVCL: - case OsAMDHSA: - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsOther: - return ZigLLVM_EABI; - case OsOpenBSD: - case OsFreeBSD: - case OsFuchsia: - case OsKFreeBSD: - case OsNetBSD: - case OsDragonFly: - case OsHurd: - case OsHaiku: - return ZigLLVM_GNU; - case OsUefi: - case OsWindows: - return ZigLLVM_MSVC; - case OsLinux: - case OsWASI: - case OsEmscripten: - return ZigLLVM_Musl; - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsPlan9: - case OsMacOSX: - case OsIOS: - case OsTvOS: - case OsWatchOS: - case OsDriverKit: - case OsShaderModel: - return ZigLLVM_UnknownEnvironment; - } - zig_unreachable(); -} - -bool target_has_debug_info(const ZigTarget *target) { - return true; -} - -bool target_long_double_is_f128(const ZigTarget *target) { - if (target->abi == ZigLLVM_MSVC) { - return false; - } - switch (target->arch) { - case ZigLLVM_aarch64: - // According to Apple's official guide: - // > The long double type is a double precision IEEE754 binary floating-point type, - // > which makes it identical to the double type. This behavior contrasts to the - // > standard specification, in which a long double is a quad-precision, IEEE754 - // > binary, floating-point type. - // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms - return !target_os_is_darwin(target->os); - - case ZigLLVM_riscv64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_systemz: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_sparc: - case ZigLLVM_sparcv9: - case ZigLLVM_sparcel: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return true; - - default: - return false; - } -} - -bool target_has_f80(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - return true; - - default: - return false; - } -} - -bool target_is_riscv(const ZigTarget *target) { - return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64; -} - -bool target_is_sparc(const ZigTarget *target) { - return target->arch == ZigLLVM_sparc || target->arch == ZigLLVM_sparcv9; -} - -bool target_is_mips(const ZigTarget *target) { - return target->arch == ZigLLVM_mips || target->arch == ZigLLVM_mipsel || - target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el; -} - -bool target_is_ppc(const ZigTarget *target) { - return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppcle || - target->arch == ZigLLVM_ppc64 || target->arch == ZigLLVM_ppc64le; -} - -// Returns the minimum alignment for every function pointer on the given -// architecture. -unsigned target_fn_ptr_align(const ZigTarget *target) { - // TODO This is a pessimization but is always correct. - return 1; -} - -// Returns the minimum alignment for every function on the given architecture. -unsigned target_fn_align(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - // TODO If the C extension is not present the value is 4. - return 2; - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - return 4; - - default: - return 1; - } -} diff --git a/src/stage1/target.hpp b/src/stage1/target.hpp deleted file mode 100644 index 2e2603354989..000000000000 --- a/src/stage1/target.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_TARGET_HPP -#define ZIG_TARGET_HPP - -#include "stage2.h" - -struct Buf; - -enum CIntType { - CIntTypeShort, - CIntTypeUShort, - CIntTypeInt, - CIntTypeUInt, - CIntTypeLong, - CIntTypeULong, - CIntTypeLongLong, - CIntTypeULongLong, - - CIntTypeCount, -}; - -Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len); -Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); -Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); - -size_t target_arch_count(void); -ZigLLVM_ArchType target_arch_enum(size_t index); -const char *target_arch_name(ZigLLVM_ArchType arch); - -const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch); - -size_t target_vendor_count(void); -ZigLLVM_VendorType target_vendor_enum(size_t index); - -size_t target_os_count(void); -Os target_os_enum(size_t index); -const char *target_os_name(Os os_type); - -size_t target_abi_count(void); -ZigLLVM_EnvironmentType target_abi_enum(size_t index); -const char *target_abi_name(ZigLLVM_EnvironmentType abi); -ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os); - - -size_t target_oformat_count(void); -ZigLLVM_ObjectFormatType target_oformat_enum(size_t index); -const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat); -ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target); - -void target_triple_llvm(Buf *triple, const ZigTarget *target); -void target_triple_zig(Buf *triple, const ZigTarget *target); - -void init_all_targets(void); - -void resolve_target_object_format(ZigTarget *target); - -uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id); - -const char *target_o_file_ext(const ZigTarget *target); -const char *target_asm_file_ext(const ZigTarget *target); -const char *target_llvm_ir_file_ext(const ZigTarget *target); - -ZigLLVM_OSType get_llvm_os_type(Os os_type); - -bool target_is_arm(const ZigTarget *target); -bool target_is_mips(const ZigTarget *target); -bool target_is_ppc(const ZigTarget *target); -bool target_allows_addr_zero(const ZigTarget *target); -bool target_has_valgrind_support(const ZigTarget *target); -bool target_os_is_darwin(Os os); -bool target_is_wasm(const ZigTarget *target); -bool target_is_bpf(const ZigTarget *target); -bool target_is_riscv(const ZigTarget *target); -bool target_is_sparc(const ZigTarget *target); -bool target_is_android(const ZigTarget *target); -bool target_has_debug_info(const ZigTarget *target); -bool target_long_double_is_f128(const ZigTarget *target); -bool target_has_f80(const ZigTarget *target); - -uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch); -uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch); - -unsigned target_fn_ptr_align(const ZigTarget *target); -unsigned target_fn_align(const ZigTarget *target); - -#endif diff --git a/src/stage1/tokenizer.cpp b/src/stage1/tokenizer.cpp deleted file mode 100644 index 820c73be5c09..000000000000 --- a/src/stage1/tokenizer.cpp +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "tokenizer.hpp" -#include "util.hpp" - -#include -#include -#include -#include -#include -#include - -#define WHITESPACE \ - ' ': \ - case '\r': \ - case '\n' - -#define DIGIT_NON_ZERO \ - '1': \ - case '2': \ - case '3': \ - case '4': \ - case '5': \ - case '6': \ - case '7': \ - case '8': \ - case '9' - -#define DIGIT \ - '0': \ - case DIGIT_NON_ZERO - -#define HEXDIGIT \ - 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'e': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'E': \ - case 'F': \ - case DIGIT - -#define ALPHA_EXCEPT_HEX_P_O_X \ - 'g': \ - case 'h': \ - case 'i': \ - case 'j': \ - case 'k': \ - case 'l': \ - case 'm': \ - case 'n': \ - case 'q': \ - case 'r': \ - case 's': \ - case 't': \ - case 'u': \ - case 'v': \ - case 'w': \ - case 'y': \ - case 'z': \ - case 'G': \ - case 'H': \ - case 'I': \ - case 'J': \ - case 'K': \ - case 'L': \ - case 'M': \ - case 'N': \ - case 'O': \ - case 'Q': \ - case 'R': \ - case 'S': \ - case 'T': \ - case 'U': \ - case 'V': \ - case 'W': \ - case 'X': \ - case 'Y': \ - case 'Z' - -#define ALPHA_EXCEPT_E_B_O_X \ - ALPHA_EXCEPT_HEX_P_O_X: \ - case 'a': \ - case 'c': \ - case 'd': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'F': \ - case 'p': \ - case 'P' - -#define ALPHA_EXCEPT_HEX_AND_P \ - ALPHA_EXCEPT_HEX_P_O_X: \ - case 'o': \ - case 'x' - -#define ALPHA_EXCEPT_E \ - ALPHA_EXCEPT_HEX_AND_P: \ - case 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'F': \ - case 'p': \ - case 'P' - -#define ALPHA \ - ALPHA_EXCEPT_E: \ - case 'e': \ - case 'E' - -#define IDENTIFIER_CHAR \ - ALPHA: \ - case DIGIT: \ - case '_' - -#define SYMBOL_START \ - ALPHA: \ - case '_' - -struct ZigKeyword { - const char *text; - TokenId token_id; -}; - -static const struct ZigKeyword zig_keywords[] = { - {"align", TokenIdKeywordAlign}, - {"allowzero", TokenIdKeywordAllowZero}, - {"and", TokenIdKeywordAnd}, - {"anyframe", TokenIdKeywordAnyFrame}, - {"anytype", TokenIdKeywordAnyType}, - {"asm", TokenIdKeywordAsm}, - {"async", TokenIdKeywordAsync}, - {"await", TokenIdKeywordAwait}, - {"break", TokenIdKeywordBreak}, - {"callconv", TokenIdKeywordCallconv}, - {"catch", TokenIdKeywordCatch}, - {"comptime", TokenIdKeywordCompTime}, - {"const", TokenIdKeywordConst}, - {"continue", TokenIdKeywordContinue}, - {"defer", TokenIdKeywordDefer}, - {"else", TokenIdKeywordElse}, - {"enum", TokenIdKeywordEnum}, - {"errdefer", TokenIdKeywordErrdefer}, - {"error", TokenIdKeywordError}, - {"export", TokenIdKeywordExport}, - {"extern", TokenIdKeywordExtern}, - {"fn", TokenIdKeywordFn}, - {"for", TokenIdKeywordFor}, - {"if", TokenIdKeywordIf}, - {"inline", TokenIdKeywordInline}, - {"noalias", TokenIdKeywordNoAlias}, - {"noinline", TokenIdKeywordNoInline}, - {"nosuspend", TokenIdKeywordNoSuspend}, - {"opaque", TokenIdKeywordOpaque}, - {"or", TokenIdKeywordOr}, - {"orelse", TokenIdKeywordOrElse}, - {"packed", TokenIdKeywordPacked}, - {"pub", TokenIdKeywordPub}, - {"resume", TokenIdKeywordResume}, - {"return", TokenIdKeywordReturn}, - {"linksection", TokenIdKeywordLinkSection}, - {"struct", TokenIdKeywordStruct}, - {"suspend", TokenIdKeywordSuspend}, - {"switch", TokenIdKeywordSwitch}, - {"test", TokenIdKeywordTest}, - {"threadlocal", TokenIdKeywordThreadLocal}, - {"try", TokenIdKeywordTry}, - {"union", TokenIdKeywordUnion}, - {"unreachable", TokenIdKeywordUnreachable}, - {"usingnamespace", TokenIdKeywordUsingNamespace}, - {"var", TokenIdKeywordVar}, - {"volatile", TokenIdKeywordVolatile}, - {"while", TokenIdKeywordWhile}, -}; - -// Returns TokenIdIdentifier if it is not a keyword. -static TokenId zig_keyword_token(const char *name_ptr, size_t name_len) { - for (size_t i = 0; i < array_length(zig_keywords); i += 1) { - if (mem_eql_str(name_ptr, name_len, zig_keywords[i].text)) { - return zig_keywords[i].token_id; - } - } - return TokenIdIdentifier; -} - -enum TokenizeState { - TokenizeState_start, - TokenizeState_identifier, - TokenizeState_builtin, - TokenizeState_string_literal, - TokenizeState_string_literal_backslash, - TokenizeState_multiline_string_literal_line, - TokenizeState_char_literal, - TokenizeState_char_literal_backslash, - TokenizeState_char_literal_hex_escape, - TokenizeState_char_literal_unicode_escape_saw_u, - TokenizeState_char_literal_unicode_escape, - TokenizeState_char_literal_unicode, - TokenizeState_char_literal_end, - TokenizeState_backslash, - TokenizeState_equal, - TokenizeState_bang, - TokenizeState_pipe, - TokenizeState_minus, - TokenizeState_minus_percent, - TokenizeState_minus_pipe, - TokenizeState_asterisk, - TokenizeState_asterisk_percent, - TokenizeState_asterisk_pipe, - TokenizeState_slash, - TokenizeState_line_comment_start, - TokenizeState_line_comment, - TokenizeState_doc_comment_start, - TokenizeState_doc_comment, - TokenizeState_container_doc_comment, - TokenizeState_zero, - TokenizeState_int_literal_dec, - TokenizeState_int_literal_dec_no_underscore, - TokenizeState_int_literal_bin, - TokenizeState_int_literal_bin_no_underscore, - TokenizeState_int_literal_oct, - TokenizeState_int_literal_oct_no_underscore, - TokenizeState_int_literal_hex, - TokenizeState_int_literal_hex_no_underscore, - TokenizeState_num_dot_dec, - TokenizeState_num_dot_hex, - TokenizeState_float_fraction_dec, - TokenizeState_float_fraction_dec_no_underscore, - TokenizeState_float_fraction_hex, - TokenizeState_float_fraction_hex_no_underscore, - TokenizeState_float_exponent_unsigned, - TokenizeState_float_exponent_num, - TokenizeState_float_exponent_num_no_underscore, - TokenizeState_ampersand, - TokenizeState_caret, - TokenizeState_percent, - TokenizeState_plus, - TokenizeState_plus_percent, - TokenizeState_plus_pipe, - TokenizeState_angle_bracket_left, - TokenizeState_angle_bracket_angle_bracket_left, - TokenizeState_angle_bracket_angle_bracket_left_pipe, - TokenizeState_angle_bracket_right, - TokenizeState_angle_bracket_angle_bracket_right, - TokenizeState_period, - TokenizeState_period_2, - TokenizeState_period_asterisk, - TokenizeState_saw_at_sign, - TokenizeState_error, -}; - - -struct Tokenize { - Tokenization *out; - size_t pos; - TokenizeState state; - uint32_t line; - uint32_t column; -}; - -ATTRIBUTE_PRINTF(2, 3) -static void tokenize_error(Tokenize *t, const char *format, ...) { - t->state = TokenizeState_error; - - t->out->err_byte_offset = t->pos; - - va_list ap; - va_start(ap, format); - t->out->err = buf_vprintf(format, ap); - va_end(ap); -} - -static void begin_token(Tokenize *t, TokenId id) { - t->out->ids.append(id); - TokenLoc tok_loc; - tok_loc.offset = (uint32_t) t->pos; - tok_loc.line = t->line; - tok_loc.column = t->column; - t->out->locs.append(tok_loc); -} - -static void cancel_token(Tokenize *t) { - t->out->ids.pop(); - t->out->locs.pop(); -} - -static const char* get_escape_shorthand(uint8_t c) { - switch (c) { - case '\0': - return "\\0"; - case '\a': - return "\\a"; - case '\b': - return "\\b"; - case '\t': - return "\\t"; - case '\n': - return "\\n"; - case '\v': - return "\\v"; - case '\f': - return "\\f"; - case '\r': - return "\\r"; - default: - return nullptr; - } -} - -static void invalid_eof(Tokenize *t) { - return tokenize_error(t, "unexpected End-Of-File"); -} - -static void invalid_char_error(Tokenize *t, uint8_t c) { - if (c == 0) { - return invalid_eof(t); - } - - if (c == '\r') { - tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported"); - return; - } - - const char *sh = get_escape_shorthand(c); - if (sh) { - tokenize_error(t, "invalid character: '%s'", sh); - return; - } - - if (isprint(c)) { - tokenize_error(t, "invalid character: '%c'", c); - return; - } - - tokenize_error(t, "invalid character: '\\x%02x'", c); -} - -void tokenize(const char *source, Tokenization *out) { - Tokenize t = {0}; - t.out = out; - - size_t remaining_code_units; - size_t seen_escape_digits; - - // Skip the UTF-8 BOM if present. - if (source[0] == (char)0xef && - source[1] == (char)0xbb && - source[2] == (char)0xbf) - { - t.pos += 3; - } - - // Invalid token takes up index 0 so that index 0 can mean "none". - begin_token(&t, TokenIdCount); - - for (;;) { - uint8_t c = source[t.pos]; - switch (t.state) { - case TokenizeState_error: - goto eof; - case TokenizeState_start: - switch (c) { - case 0: - goto eof; - case WHITESPACE: - break; - case '"': - begin_token(&t, TokenIdStringLiteral); - t.state = TokenizeState_string_literal; - break; - case '\'': - begin_token(&t, TokenIdCharLiteral); - t.state = TokenizeState_char_literal; - break; - case ALPHA: - case '_': - t.state = TokenizeState_identifier; - begin_token(&t, TokenIdIdentifier); - break; - case '@': - begin_token(&t, TokenIdBuiltin); - t.state = TokenizeState_saw_at_sign; - break; - case '=': - begin_token(&t, TokenIdEq); - t.state = TokenizeState_equal; - break; - case '!': - begin_token(&t, TokenIdBang); - t.state = TokenizeState_bang; - break; - case '|': - begin_token(&t, TokenIdBinOr); - t.state = TokenizeState_pipe; - break; - case '(': - begin_token(&t, TokenIdLParen); - break; - case ')': - begin_token(&t, TokenIdRParen); - break; - case '[': - begin_token(&t, TokenIdLBracket); - break; - case ']': - begin_token(&t, TokenIdRBracket); - break; - case ';': - begin_token(&t, TokenIdSemicolon); - break; - case ',': - begin_token(&t, TokenIdComma); - break; - case '?': - begin_token(&t, TokenIdQuestion); - break; - case ':': - begin_token(&t, TokenIdColon); - break; - case '%': - begin_token(&t, TokenIdPercent); - t.state = TokenizeState_percent; - break; - case '*': - begin_token(&t, TokenIdStar); - t.state = TokenizeState_asterisk; - break; - case '+': - begin_token(&t, TokenIdPlus); - t.state = TokenizeState_plus; - break; - case '<': - begin_token(&t, TokenIdCmpLessThan); - t.state = TokenizeState_angle_bracket_left; - break; - case '>': - begin_token(&t, TokenIdCmpGreaterThan); - t.state = TokenizeState_angle_bracket_right; - break; - case '^': - begin_token(&t, TokenIdBinXor); - t.state = TokenizeState_caret; - break; - case '\\': - begin_token(&t, TokenIdMultilineStringLiteralLine); - t.state = TokenizeState_backslash; - break; - case '{': - begin_token(&t, TokenIdLBrace); - break; - case '}': - begin_token(&t, TokenIdRBrace); - break; - case '~': - begin_token(&t, TokenIdTilde); - break; - case '.': - begin_token(&t, TokenIdDot); - t.state = TokenizeState_period; - break; - case '-': - begin_token(&t, TokenIdDash); - t.state = TokenizeState_minus; - break; - case '/': - begin_token(&t, TokenIdSlash); - t.state = TokenizeState_slash; - break; - case '&': - begin_token(&t, TokenIdAmpersand); - t.state = TokenizeState_ampersand; - break; - case '0': - t.state = TokenizeState_zero; - begin_token(&t, TokenIdIntLiteral); - break; - case DIGIT_NON_ZERO: - t.state = TokenizeState_int_literal_dec; - begin_token(&t, TokenIdIntLiteral); - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_saw_at_sign: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '"': - t.out->ids.last() = TokenIdIdentifier; - t.state = TokenizeState_string_literal; - break; - case IDENTIFIER_CHAR: - t.state = TokenizeState_builtin; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_ampersand: - switch (c) { - case 0: - goto eof; - case '&': - tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND"); - break; - case '=': - t.out->ids.last() = TokenIdBitAndEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesEq; - t.state = TokenizeState_start; - break; - case '*': - t.out->ids.last() = TokenIdStarStar; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_asterisk_percent; - break; - case '|': - t.state = TokenizeState_asterisk_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdTimesPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdTimesPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdTimesPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdTimesPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_percent: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdModEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusEq; - t.state = TokenizeState_start; - break; - case '+': - t.out->ids.last() = TokenIdPlusPlus; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_plus_percent; - break; - case '|': - t.state = TokenizeState_plus_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdPlusPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdPlusPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdPlusPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdPlusPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_caret: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdBitXorEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_identifier: - switch (c) { - case 0: { - uint32_t start_pos = t.out->locs.last().offset; - t.out->ids.last() = zig_keyword_token( - source + start_pos, t.pos - start_pos); - goto eof; - } - case IDENTIFIER_CHAR: - break; - default: { - uint32_t start_pos = t.out->locs.last().offset; - t.out->ids.last() = zig_keyword_token( - source + start_pos, t.pos - start_pos); - - t.state = TokenizeState_start; - continue; - } - } - break; - case TokenizeState_builtin: - switch (c) { - case 0: - goto eof; - case IDENTIFIER_CHAR: - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_backslash: - switch (c) { - case '\\': - t.state = TokenizeState_multiline_string_literal_line; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_string_literal: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\\': - t.state = TokenizeState_string_literal_backslash; - break; - case '"': - t.state = TokenizeState_start; - break; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in string literal"); - break; - default: - break; - } - break; - case TokenizeState_string_literal_backslash: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in string literal"); - break; - default: - t.state = TokenizeState_string_literal; - break; - } - break; - case TokenizeState_char_literal: - if (c == 0) { - invalid_eof(&t); - goto eof; - } else if (c == '\\') { - t.state = TokenizeState_char_literal_backslash; - } else if (c == '\'') { - tokenize_error(&t, "expected character"); - } else if ((c >= 0x80 && c <= 0xbf) || c >= 0xf8) { - // 10xxxxxx - // 11111xxx - invalid_char_error(&t, c); - } else if (c >= 0xc0 && c <= 0xdf) { - // 110xxxxx - remaining_code_units = 1; - t.state = TokenizeState_char_literal_unicode; - } else if (c >= 0xe0 && c <= 0xef) { - // 1110xxxx - remaining_code_units = 2; - t.state = TokenizeState_char_literal_unicode; - } else if (c >= 0xf0 && c <= 0xf7) { - // 11110xxx - remaining_code_units = 3; - t.state = TokenizeState_char_literal_unicode; - } else { - t.state = TokenizeState_char_literal_end; - } - break; - case TokenizeState_char_literal_backslash: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in character literal"); - break; - case 'x': - t.state = TokenizeState_char_literal_hex_escape; - seen_escape_digits = 0; - break; - case 'u': - t.state = TokenizeState_char_literal_unicode_escape_saw_u; - break; - case 'U': - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_char_literal_end; - break; - } - break; - case TokenizeState_char_literal_hex_escape: - switch (c) { - case ALPHA: - case DIGIT: - seen_escape_digits += 1; - if (seen_escape_digits == 2) { - t.state = TokenizeState_char_literal_end; - } - break; - default: - tokenize_error(&t, "expected hex digit"); - break; - } - break; - case TokenizeState_char_literal_unicode_escape_saw_u: - switch (c) { - case '{': - t.state = TokenizeState_char_literal_unicode_escape; - seen_escape_digits = 0; - break; - default: - tokenize_error(&t, "expected '{' to begin unicode escape sequence"); - break; - } - break; - case TokenizeState_char_literal_unicode_escape: - switch (c) { - case ALPHA: - case DIGIT: - seen_escape_digits += 1; - break; - case '}': - if (seen_escape_digits == 0) { - tokenize_error(&t, "empty unicode escape sequence"); - break; - } - t.state = TokenizeState_char_literal_end; - break; - default: - tokenize_error(&t, "expected hex digit"); - break; - } - break; - case TokenizeState_char_literal_end: - switch (c) { - case '\'': - t.state = TokenizeState_start; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_char_literal_unicode: - if (c >= 0x80 && c <= 0xbf) { - remaining_code_units -= 1; - if (remaining_code_units == 0) { - t.state = TokenizeState_char_literal_end; - } - } else { - invalid_char_error(&t, c); - } - break; - case TokenizeState_multiline_string_literal_line: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - break; - } - break; - case TokenizeState_bang: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpNotEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_pipe: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdBitOrEq; - t.state = TokenizeState_start; - break; - case '|': - t.out->ids.last() = TokenIdBarBar; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_equal: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpEq; - t.state = TokenizeState_start; - break; - case '>': - t.out->ids.last() = TokenIdFatArrow; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus: - switch (c) { - case 0: - goto eof; - case '>': - t.out->ids.last() = TokenIdArrow; - t.state = TokenizeState_start; - break; - case '=': - t.out->ids.last() = TokenIdMinusEq; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_minus_percent; - break; - case '|': - t.state = TokenizeState_minus_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdMinusPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdMinusPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdMinusPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdMinusPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdMinusPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdMinusPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_left: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpLessOrEq; - t.state = TokenizeState_start; - break; - case '<': - t.state = TokenizeState_angle_bracket_angle_bracket_left; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_left: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftLeft; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftLeftEq; - t.state = TokenizeState_start; - break; - case '|': - t.state = TokenizeState_angle_bracket_angle_bracket_left_pipe; - break; - default: - t.out->ids.last() = TokenIdBitShiftLeft; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_left_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftLeftPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftLeftPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdBitShiftLeftPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_right: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpGreaterOrEq; - t.state = TokenizeState_start; - break; - case '>': - t.state = TokenizeState_angle_bracket_angle_bracket_right; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_right: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftRight; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftRightEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdBitShiftRight; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period: - switch (c) { - case 0: - goto eof; - case '.': - t.state = TokenizeState_period_2; - break; - case '*': - t.state = TokenizeState_period_asterisk; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period_2: - switch (c) { - case 0: - t.out->ids.last() = TokenIdEllipsis2; - goto eof; - case '.': - t.out->ids.last() = TokenIdEllipsis3; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdEllipsis2; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period_asterisk: - switch (c) { - case 0: - t.out->ids.last() = TokenIdDotStar; - goto eof; - case '*': - tokenize_error(&t, "`.*` cannot be followed by `*`. Are you missing a space?"); - break; - default: - t.out->ids.last() = TokenIdDotStar; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_slash: - switch (c) { - case 0: - goto eof; - case '/': - t.state = TokenizeState_line_comment_start; - break; - case '=': - t.out->ids.last() = TokenIdDivEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_line_comment_start: - switch (c) { - case 0: - goto eof; - case '/': - t.state = TokenizeState_doc_comment_start; - break; - case '!': - t.out->ids.last() = TokenIdContainerDocComment; - t.state = TokenizeState_container_doc_comment; - break; - case '\n': - cancel_token(&t); - t.state = TokenizeState_start; - break; - default: - cancel_token(&t); - t.state = TokenizeState_line_comment; - break; - } - break; - case TokenizeState_doc_comment_start: - switch (c) { - case 0: - t.out->ids.last() = TokenIdDocComment; - goto eof; - case '/': - cancel_token(&t); - t.state = TokenizeState_line_comment; - break; - case '\n': - t.out->ids.last() = TokenIdDocComment; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdDocComment; - t.state = TokenizeState_doc_comment; - break; - } - break; - case TokenizeState_line_comment: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - break; - } - break; - case TokenizeState_doc_comment: - case TokenizeState_container_doc_comment: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - // do nothing - break; - } - break; - case TokenizeState_zero: - switch (c) { - case 0: - goto eof; - case 'b': - t.state = TokenizeState_int_literal_bin_no_underscore; - break; - case 'o': - t.state = TokenizeState_int_literal_oct_no_underscore; - break; - case 'x': - t.state = TokenizeState_int_literal_hex_no_underscore; - break; - case DIGIT: - case '_': - case '.': - case 'e': - case 'E': - // Reinterpret as a decimal number. - t.state = TokenizeState_int_literal_dec; - continue; - case ALPHA_EXCEPT_E_B_O_X: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_bin_no_underscore: - switch (c) { - case '0': - case '1': - t.state = TokenizeState_int_literal_bin; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_int_literal_bin: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_bin_no_underscore; - break; - case '0': - case '1': - break; - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case ALPHA: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_oct_no_underscore: - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - t.state = TokenizeState_int_literal_oct; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_int_literal_oct: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_oct_no_underscore; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - break; - case ALPHA: - case '8': - case '9': - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_dec_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_int_literal_dec; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_int_literal_dec: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_dec_no_underscore; - break; - case '.': - t.state = TokenizeState_num_dot_dec; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case 'e': - case 'E': - t.state = TokenizeState_float_exponent_unsigned; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case DIGIT: - break; - case ALPHA_EXCEPT_E: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_hex_no_underscore: - switch (c) { - case HEXDIGIT: - t.state = TokenizeState_int_literal_hex; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_int_literal_hex: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_hex_no_underscore; - break; - case '.': - t.state = TokenizeState_num_dot_hex; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case 'p': - case 'P': - t.state = TokenizeState_float_exponent_unsigned; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case HEXDIGIT: - break; - case ALPHA_EXCEPT_HEX_AND_P: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_num_dot_dec: - switch (c) { - case 0: - goto eof; - case '.': - t.out->ids.last() = TokenIdIntLiteral; - t.pos -= 1; - t.column -= 1; - t.state = TokenizeState_start; - continue; - case DIGIT: - t.state = TokenizeState_float_fraction_dec; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_num_dot_hex: - switch (c) { - case 0: - goto eof; - case '.': - t.out->ids.last() = TokenIdIntLiteral; - t.pos -= 1; - t.column -= 1; - t.state = TokenizeState_start; - continue; - case HEXDIGIT: - t.out->ids.last() = TokenIdFloatLiteral; - t.state = TokenizeState_float_fraction_hex; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_float_fraction_dec_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_float_fraction_dec; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_fraction_dec: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_fraction_dec_no_underscore; - break; - case 'e': - case 'E': - t.state = TokenizeState_float_exponent_unsigned; - break; - case DIGIT: - break; - case ALPHA_EXCEPT_E: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_float_fraction_hex_no_underscore: - switch (c) { - case HEXDIGIT: - t.state = TokenizeState_float_fraction_hex; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_fraction_hex: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_fraction_hex_no_underscore; - break; - case 'p': - case 'P': - t.state = TokenizeState_float_exponent_unsigned; - break; - case HEXDIGIT: - break; - case ALPHA_EXCEPT_HEX_AND_P: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_float_exponent_unsigned: - switch (c) { - case '+': - case '-': - t.state = TokenizeState_float_exponent_num_no_underscore; - break; - default: - // Reinterpret as a normal exponent number. - t.state = TokenizeState_float_exponent_num_no_underscore; - continue; - } - break; - case TokenizeState_float_exponent_num_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_float_exponent_num; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_exponent_num: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_exponent_num_no_underscore; - break; - case DIGIT: - break; - case ALPHA: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - } - t.pos += 1; - if (c == '\n') { - t.line += 1; - t.column = 0; - } else { - t.column += 1; - } - } -eof:; - - begin_token(&t, TokenIdEof); -} - -const char * token_name(TokenId id) { - switch (id) { - case TokenIdAmpersand: return "&"; - case TokenIdArrow: return "->"; - case TokenIdBang: return "!"; - case TokenIdBarBar: return "||"; - case TokenIdBinOr: return "|"; - case TokenIdBinXor: return "^"; - case TokenIdBitAndEq: return "&="; - case TokenIdBitOrEq: return "|="; - case TokenIdBitShiftLeft: return "<<"; - case TokenIdBitShiftLeftEq: return "<<="; - case TokenIdBitShiftLeftPipe: return "<<|"; - case TokenIdBitShiftLeftPipeEq: return "<<|="; - case TokenIdBitShiftRight: return ">>"; - case TokenIdBitShiftRightEq: return ">>="; - case TokenIdBitXorEq: return "^="; - case TokenIdCharLiteral: return "CharLiteral"; - case TokenIdCmpEq: return "=="; - case TokenIdCmpGreaterOrEq: return ">="; - case TokenIdCmpGreaterThan: return ">"; - case TokenIdCmpLessOrEq: return "<="; - case TokenIdCmpLessThan: return "<"; - case TokenIdCmpNotEq: return "!="; - case TokenIdColon: return ":"; - case TokenIdComma: return ","; - case TokenIdDash: return "-"; - case TokenIdDivEq: return "/="; - case TokenIdDocComment: return "DocComment"; - case TokenIdContainerDocComment: return "ContainerDocComment"; - case TokenIdDot: return "."; - case TokenIdDotStar: return ".*"; - case TokenIdEllipsis2: return ".."; - case TokenIdEllipsis3: return "..."; - case TokenIdEof: return "EOF"; - case TokenIdEq: return "="; - case TokenIdFatArrow: return "=>"; - case TokenIdFloatLiteral: return "FloatLiteral"; - case TokenIdIntLiteral: return "IntLiteral"; - case TokenIdKeywordAsync: return "async"; - case TokenIdKeywordAllowZero: return "allowzero"; - case TokenIdKeywordAwait: return "await"; - case TokenIdKeywordResume: return "resume"; - case TokenIdKeywordSuspend: return "suspend"; - case TokenIdKeywordAlign: return "align"; - case TokenIdKeywordAnd: return "and"; - case TokenIdKeywordAnyFrame: return "anyframe"; - case TokenIdKeywordAnyType: return "anytype"; - case TokenIdKeywordAsm: return "asm"; - case TokenIdKeywordBreak: return "break"; - case TokenIdKeywordCatch: return "catch"; - case TokenIdKeywordCallconv: return "callconv"; - case TokenIdKeywordCompTime: return "comptime"; - case TokenIdKeywordConst: return "const"; - case TokenIdKeywordContinue: return "continue"; - case TokenIdKeywordDefer: return "defer"; - case TokenIdKeywordElse: return "else"; - case TokenIdKeywordEnum: return "enum"; - case TokenIdKeywordErrdefer: return "errdefer"; - case TokenIdKeywordError: return "error"; - case TokenIdKeywordExport: return "export"; - case TokenIdKeywordExtern: return "extern"; - case TokenIdKeywordFn: return "fn"; - case TokenIdKeywordFor: return "for"; - case TokenIdKeywordIf: return "if"; - case TokenIdKeywordInline: return "inline"; - case TokenIdKeywordNoAlias: return "noalias"; - case TokenIdKeywordNoInline: return "noinline"; - case TokenIdKeywordNoSuspend: return "nosuspend"; - case TokenIdKeywordOpaque: return "opaque"; - case TokenIdKeywordOr: return "or"; - case TokenIdKeywordOrElse: return "orelse"; - case TokenIdKeywordPacked: return "packed"; - case TokenIdKeywordPub: return "pub"; - case TokenIdKeywordReturn: return "return"; - case TokenIdKeywordLinkSection: return "linksection"; - case TokenIdKeywordStruct: return "struct"; - case TokenIdKeywordSwitch: return "switch"; - case TokenIdKeywordTest: return "test"; - case TokenIdKeywordThreadLocal: return "threadlocal"; - case TokenIdKeywordTry: return "try"; - case TokenIdKeywordUnion: return "union"; - case TokenIdKeywordUnreachable: return "unreachable"; - case TokenIdKeywordUsingNamespace: return "usingnamespace"; - case TokenIdKeywordVar: return "var"; - case TokenIdKeywordVolatile: return "volatile"; - case TokenIdKeywordWhile: return "while"; - case TokenIdLBrace: return "{"; - case TokenIdLBracket: return "["; - case TokenIdLParen: return "("; - case TokenIdQuestion: return "?"; - case TokenIdMinusEq: return "-="; - case TokenIdMinusPercent: return "-%"; - case TokenIdMinusPercentEq: return "-%="; - case TokenIdMinusPipe: return "-|"; - case TokenIdMinusPipeEq: return "-|="; - case TokenIdModEq: return "%="; - case TokenIdPercent: return "%"; - case TokenIdPlus: return "+"; - case TokenIdPlusEq: return "+="; - case TokenIdPlusPercent: return "+%"; - case TokenIdPlusPercentEq: return "+%="; - case TokenIdPlusPipe: return "+|"; - case TokenIdPlusPipeEq: return "+|="; - case TokenIdPlusPlus: return "++"; - case TokenIdRBrace: return "}"; - case TokenIdRBracket: return "]"; - case TokenIdRParen: return ")"; - case TokenIdSemicolon: return ";"; - case TokenIdSlash: return "/"; - case TokenIdStar: return "*"; - case TokenIdStarStar: return "**"; - case TokenIdStringLiteral: return "StringLiteral"; - case TokenIdMultilineStringLiteralLine: return "MultilineStringLiteralLine"; - case TokenIdIdentifier: return "Identifier"; - case TokenIdTilde: return "~"; - case TokenIdTimesEq: return "*="; - case TokenIdTimesPercent: return "*%"; - case TokenIdTimesPercentEq: return "*%="; - case TokenIdTimesPipe: return "*|"; - case TokenIdTimesPipeEq: return "*|="; - case TokenIdBuiltin: return "Builtin"; - case TokenIdCount: - zig_unreachable(); - } - return "(invalid token)"; -} diff --git a/src/stage1/tokenizer.hpp b/src/stage1/tokenizer.hpp deleted file mode 100644 index e2cb96e866f0..000000000000 --- a/src/stage1/tokenizer.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_TOKENIZER_HPP -#define ZIG_TOKENIZER_HPP - -#include "buffer.hpp" -#include "bigint.hpp" -#include "bigfloat.hpp" - -enum TokenId : uint8_t { - TokenIdAmpersand, - TokenIdArrow, - TokenIdBang, - TokenIdBarBar, - TokenIdBinOr, - TokenIdBinXor, - TokenIdBitAndEq, - TokenIdBitOrEq, - TokenIdBitShiftLeft, - TokenIdBitShiftLeftEq, - TokenIdBitShiftLeftPipe, - TokenIdBitShiftLeftPipeEq, - TokenIdBitShiftRight, - TokenIdBitShiftRightEq, - TokenIdBitXorEq, - TokenIdBuiltin, - TokenIdCharLiteral, - TokenIdCmpEq, - TokenIdCmpGreaterOrEq, - TokenIdCmpGreaterThan, - TokenIdCmpLessOrEq, - TokenIdCmpLessThan, - TokenIdCmpNotEq, - TokenIdColon, - TokenIdComma, - TokenIdDash, - TokenIdDivEq, - TokenIdDocComment, - TokenIdContainerDocComment, - TokenIdDot, - TokenIdDotStar, - TokenIdEllipsis2, - TokenIdEllipsis3, - TokenIdEof, - TokenIdEq, - TokenIdFatArrow, - TokenIdFloatLiteral, - TokenIdIntLiteral, - TokenIdKeywordAlign, - TokenIdKeywordAllowZero, - TokenIdKeywordAnd, - TokenIdKeywordAnyFrame, - TokenIdKeywordAnyType, - TokenIdKeywordAsm, - TokenIdKeywordAsync, - TokenIdKeywordAwait, - TokenIdKeywordBreak, - TokenIdKeywordCatch, - TokenIdKeywordCallconv, - TokenIdKeywordCompTime, - TokenIdKeywordConst, - TokenIdKeywordContinue, - TokenIdKeywordDefer, - TokenIdKeywordElse, - TokenIdKeywordEnum, - TokenIdKeywordErrdefer, - TokenIdKeywordError, - TokenIdKeywordExport, - TokenIdKeywordExtern, - TokenIdKeywordFn, - TokenIdKeywordFor, - TokenIdKeywordIf, - TokenIdKeywordInline, - TokenIdKeywordNoInline, - TokenIdKeywordLinkSection, - TokenIdKeywordNoAlias, - TokenIdKeywordNoSuspend, - TokenIdKeywordOpaque, - TokenIdKeywordOr, - TokenIdKeywordOrElse, - TokenIdKeywordPacked, - TokenIdKeywordPub, - TokenIdKeywordResume, - TokenIdKeywordReturn, - TokenIdKeywordStruct, - TokenIdKeywordSuspend, - TokenIdKeywordSwitch, - TokenIdKeywordTest, - TokenIdKeywordThreadLocal, - TokenIdKeywordTry, - TokenIdKeywordUnion, - TokenIdKeywordUnreachable, - TokenIdKeywordUsingNamespace, - TokenIdKeywordVar, - TokenIdKeywordVolatile, - TokenIdKeywordWhile, - TokenIdLBrace, - TokenIdLBracket, - TokenIdLParen, - TokenIdQuestion, - TokenIdMinusEq, - TokenIdMinusPercent, - TokenIdMinusPercentEq, - TokenIdMinusPipe, - TokenIdMinusPipeEq, - TokenIdModEq, - TokenIdPercent, - TokenIdPlus, - TokenIdPlusEq, - TokenIdPlusPercent, - TokenIdPlusPercentEq, - TokenIdPlusPipe, - TokenIdPlusPipeEq, - TokenIdPlusPlus, - TokenIdRBrace, - TokenIdRBracket, - TokenIdRParen, - TokenIdSemicolon, - TokenIdSlash, - TokenIdStar, - TokenIdStarStar, - TokenIdStringLiteral, - TokenIdMultilineStringLiteralLine, - TokenIdIdentifier, - TokenIdTilde, - TokenIdTimesEq, - TokenIdTimesPercent, - TokenIdTimesPercentEq, - TokenIdTimesPipe, - TokenIdTimesPipeEq, - - TokenIdCount, -}; - -typedef uint32_t TokenIndex; - -struct TokenLoc { - uint32_t offset; - uint32_t line; - uint32_t column; -}; - -struct Tokenization { - ZigList ids; - ZigList locs; - - // if an error occurred - Buf *err; - uint32_t err_byte_offset; -}; - -void tokenize(const char *source, Tokenization *out_tokenization); - -const char * token_name(TokenId id); - -#endif diff --git a/src/stage1/util.cpp b/src/stage1/util.cpp deleted file mode 100644 index e1e167adf918..000000000000 --- a/src/stage1/util.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "util.hpp" -#include "stage2.h" - -#include -#include - -void zig_panic(const char *format, ...) { - va_list ap; - va_start(ap, format); - vfprintf(stderr, format, ap); - fflush(stderr); - va_end(ap); - stage2_panic("", 0); - abort(); -} - -// Ported from std/mem.zig. -bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { - for (size_t i = 0; i < self->split_bytes.len; i += 1) { - if (byte == self->split_bytes.ptr[i]) { - return true; - } - } - return false; -} - -// Ported from std/mem.zig. -Optional> SplitIterator_next(SplitIterator *self) { - // move to beginning of token - while (self->index < self->buffer.len && - SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t start = self->index; - if (start == self->buffer.len) { - return {}; - } - - // move to end of token - while (self->index < self->buffer.len && - !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t end = self->index; - - return Optional>::some(self->buffer.slice(start, end)); -} - -// Ported from std/mem.zig. -// This one won't collapse multiple separators into one, so you could use it, for example, -// to parse Comma Separated Value format. -Optional> SplitIterator_next_separate(SplitIterator *self) { - // move to beginning of token - if (self->index < self->buffer.len && - SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t start = self->index; - if (start == self->buffer.len) { - return {}; - } - - // move to end of token - while (self->index < self->buffer.len && - !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t end = self->index; - - return Optional>::some(self->buffer.slice(start, end)); -} - -// Ported from std/mem.zig -Slice SplitIterator_rest(SplitIterator *self) { - // move to beginning of token - size_t index = self->index; - while (index < self->buffer.len && SplitIterator_isSplitByte(self, self->buffer.ptr[index])) { - index += 1; - } - return self->buffer.sliceFrom(index); -} - -// Ported from std/mem.zig -SplitIterator memSplit(Slice buffer, Slice split_bytes) { - return SplitIterator{0, buffer, split_bytes}; -} - -void zig_pretty_print_bytes(FILE *f, double n) { - if (n > 1024.0 * 1024.0 * 1024.0) { - fprintf(f, "%.03f GiB", n / 1024.0 / 1024.0 / 1024.0); - return; - } - if (n > 1024.0 * 1024.0) { - fprintf(f, "%.03f MiB", n / 1024.0 / 1024.0); - return; - } - if (n > 1024.0) { - fprintf(f, "%.03f KiB", n / 1024.0); - return; - } - fprintf(f, "%.03f bytes", n ); - return; -} - diff --git a/src/stage1/util.hpp b/src/stage1/util.hpp deleted file mode 100644 index 35fa49acce5f..000000000000 --- a/src/stage1/util.hpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_UTIL_HPP -#define ZIG_UTIL_HPP - -#include -#include -#include -#include - -#if defined(_MSC_VER) -#include -#endif - -#define ZIG_Q(x) #x -#define ZIG_QUOTE(x) ZIG_Q(x) - -#include "util_base.hpp" -#include "heap.hpp" -#include "mem.hpp" - -#if defined(_MSC_VER) -static inline int clzll(unsigned long long mask) { - unsigned long lz; -#if defined(_WIN64) - if (_BitScanReverse64(&lz, mask)) - return static_cast(63 - lz); - zig_unreachable(); -#else - if (_BitScanReverse(&lz, mask >> 32)) - lz += 32; - else - _BitScanReverse(&lz, mask & 0xffffffff); - return 63 - lz; -#endif -} -static inline int ctzll(unsigned long long mask) { - unsigned long result; -#if defined(_WIN64) - if (_BitScanForward64(&result, mask)) - return result; - zig_unreachable(); -#else - if (_BitScanForward(&result, mask & 0xffffffff)) - return result; - if (_BitScanForward(&result, mask >> 32)) - return 32 + result; - zig_unreachable(); -#endif -} -#else -#define clzll(x) __builtin_clzll(x) -#define ctzll(x) __builtin_ctzll(x) -#endif - -template -constexpr size_t array_length(const T (&)[n]) { - return n; -} - -template -static inline T max(T a, T b) { - return (a >= b) ? a : b; -} - -template -static inline T min(T a, T b) { - return (a <= b) ? a : b; -} - -template -static inline T clamp(T min_value, T value, T max_value) { - return max(min(value, max_value), min_value); -} - -static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) { - if (a_len != b_len) - return false; - return memcmp(a_ptr, b_ptr, a_len) == 0; -} -static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) { - if (a_len != b_len) - return false; - for (size_t i = 0; i < a_len; i += 1) { - if (tolower(a_ptr[i]) != tolower(b_ptr[i])) - return false; - } - return true; -} - -static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) { - return mem_eql_mem(mem, mem_len, str, strlen(str)); -} - -static inline bool str_eql_str(const char *a, const char* b) { - return mem_eql_mem(a, strlen(a), b, strlen(b)); -} - -static inline bool str_eql_str_ignore_case(const char *a, const char* b) { - return mem_eql_mem_ignore_case(a, strlen(a), b, strlen(b)); -} - -static inline bool is_power_of_2(uint64_t x) { - return x != 0 && ((x & (~x + 1)) == x); -} - -static inline bool mem_ends_with_mem(const char *mem, size_t mem_len, const char *end, size_t end_len) { - if (mem_len < end_len) return false; - return memcmp(mem + mem_len - end_len, end, end_len) == 0; -} - -static inline bool mem_ends_with_str(const char *mem, size_t mem_len, const char *str) { - return mem_ends_with_mem(mem, mem_len, str, strlen(str)); -} - -static inline uint64_t round_to_next_power_of_2(uint64_t x) { - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x |= x >> 32; - return x + 1; -} - -static inline uint8_t log2_u64(uint64_t x) { - return (63 - clzll(x)); -} - -void zig_pretty_print_bytes(FILE *f, double n); - -template -struct Optional { - T value; - bool is_some; - - static inline Optional some(T x) { - return {x, true}; - } - - static inline Optional none() { - return {{}, false}; - } - - inline bool unwrap(T *res) { - *res = value; - return is_some; - } -}; - -template -struct Slice { - T *ptr; - size_t len; - - inline T &at(size_t i) { - assert(i < len); - return ptr[i]; - } - - inline Slice slice(size_t start, size_t end) { - assert(end <= len); - assert(end >= start); - return { - ptr + start, - end - start, - }; - } - - inline Slice sliceFrom(size_t start) { - assert(start <= len); - return { - ptr + start, - len - start, - }; - } - - static inline Slice alloc(size_t n) { - return {heap::c_allocator.allocate_nonzero(n), n}; - } -}; - -template -struct Array { - static const size_t len = n; - T items[n]; - - inline Slice slice() { - return { - &items[0], - len, - }; - } -}; - -static inline Slice str(const char *literal) { - return {(uint8_t*)(literal), strlen(literal)}; -} - -// Ported from std/mem.zig -template -static inline bool memEql(Slice a, Slice b) { - if (a.len != b.len) - return false; - for (size_t i = 0; i < a.len; i += 1) { - if (a.ptr[i] != b.ptr[i]) - return false; - } - return true; -} - -// Ported from std/mem.zig -template -static inline bool memStartsWith(Slice haystack, Slice needle) { - if (needle.len > haystack.len) - return false; - return memEql(haystack.slice(0, needle.len), needle); -} - -// Ported from std/mem.zig -template -static inline void memCopy(Slice dest, Slice src) { - assert(dest.len >= src.len); - memcpy(dest.ptr, src.ptr, src.len * sizeof(T)); -} - -// Ported from std/mem.zig. -// Coordinate struct fields with memSplit function -struct SplitIterator { - size_t index; - Slice buffer; - Slice split_bytes; -}; - -bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); -Optional< Slice > SplitIterator_next(SplitIterator *self); -Optional< Slice > SplitIterator_next_separate(SplitIterator *self); -Slice SplitIterator_rest(SplitIterator *self); -SplitIterator memSplit(Slice buffer, Slice split_bytes); - -#endif diff --git a/src/stage1/util_base.hpp b/src/stage1/util_base.hpp deleted file mode 100644 index da1d3bf234de..000000000000 --- a/src/stage1/util_base.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_UTIL_BASE_HPP -#define ZIG_UTIL_BASE_HPP - -#include - -#if defined(_MSC_VER) - -#define ATTRIBUTE_COLD __declspec(noinline) -#define ATTRIBUTE_PRINTF(a, b) -#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) -#define ATTRIBUTE_NORETURN __declspec(noreturn) -#define ATTRIBUTE_MUST_USE - -#define BREAKPOINT __debugbreak() - -#else - -#define ATTRIBUTE_COLD __attribute__((cold)) -#define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b))) -#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) -#define ATTRIBUTE_NORETURN __attribute__((noreturn)) -#define ATTRIBUTE_MUST_USE __attribute__((warn_unused_result)) - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define BREAKPOINT __debugbreak() -#elif defined(__i386__) || defined(__x86_64__) -#define BREAKPOINT __asm__ volatile("int $0x03"); -#elif defined(__clang__) -#define BREAKPOINT __builtin_debugtrap() -#elif defined(__GNUC__) -#define BREAKPOINT __builtin_trap() -#else -#include -#define BREAKPOINT raise(SIGTRAP) -#endif - -#endif - -ATTRIBUTE_COLD -ATTRIBUTE_NORETURN -ATTRIBUTE_PRINTF(1, 2) -void zig_panic(const char *format, ...); - -static inline void zig_assert(bool ok, const char *file, int line, const char *func) { - if (!ok) { - zig_panic("Assertion failed at %s:%d in %s. This is a bug in the Zig compiler.", file, line, func); - } -} - -#ifdef _WIN32 -#define __func__ __FUNCTION__ -#endif - -#define zig_unreachable() zig_panic("Unreachable at %s:%d in %s. This is a bug in the Zig compiler.", __FILE__, __LINE__, __func__) - -// Assertions in stage1 are always on, and they call zig @panic. -#undef assert -#define assert(ok) zig_assert(ok, __FILE__, __LINE__, __func__) - -#if defined(_MSC_VER) -#define ZIG_FALLTHROUGH -#elif defined(__clang__) -#define ZIG_FALLTHROUGH [[clang::fallthrough]] -#elif defined(__GNUC__) && __GNUC__ >= 7 -#define ZIG_FALLTHROUGH __attribute__((fallthrough)) -#else -#define ZIG_FALLTHROUGH -#endif - -#endif diff --git a/src/stage1/zig0.cpp b/src/stage1/zig0.cpp deleted file mode 100644 index 96d33a093c81..000000000000 --- a/src/stage1/zig0.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file is the entry point for zig0, which is *only* used to build -// stage2, the self-hosted compiler, into an object file, which is then -// linked by the same build system (cmake) that linked this binary. - -#include "stage1.h" -#include "heap.hpp" -#include "stage2.h" -#include "target.hpp" -#include "error.hpp" -#include "util.hpp" -#include "buffer.hpp" -#include "os.hpp" - -#ifndef ZIG_VERSION_STRING -#include "config.h" -#endif - -#include -#include - -static int print_error_usage(const char *arg0) { - fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0); - return EXIT_FAILURE; -} - -static int print_full_usage(const char *arg0, FILE *file, int return_code) { - fprintf(file, - "Usage: %s [options] builds an object file\n" - "\n" - "Options:\n" - " --color [auto|off|on] enable or disable colored error messages\n" - " --name [name] override output name\n" - " -femit-bin=[path] Output machine code\n" - " -fcompiler-rt Always include compiler-rt symbols in output\n" - " --pkg-begin [name] [path] make pkg available to import and push current pkg\n" - " --pkg-end pop current pkg\n" - " -ODebug build with optimizations off and safety on\n" - " -OReleaseFast build with optimizations on and safety off\n" - " -OReleaseSafe build with optimizations on and safety on\n" - " -OReleaseSmall build with size optimizations on and safety off\n" - " -fsingle-threaded source may assume it is only used single-threaded\n" - " -dynamic create a shared library (.so; .dll; .dylib)\n" - " --strip exclude debug symbols\n" - " -target [name] -- see the targets command\n" - " -mcpu [cpu] specify target CPU and feature set\n" - " --verbose-ir enable compiler debug output for Zig IR\n" - " --verbose-llvm-ir enable compiler debug output for LLVM IR\n" - " --verbose-cimport enable compiler debug output for C imports\n" - " --verbose-llvm-cpu-features enable compiler debug output for LLVM CPU features\n" - "\n" - , arg0); - return return_code; -} - -static Os get_zig_os_type(ZigLLVM_OSType os_type) { - switch (os_type) { - case ZigLLVM_UnknownOS: - return OsFreestanding; - case ZigLLVM_Ananas: - return OsAnanas; - case ZigLLVM_CloudABI: - return OsCloudABI; - case ZigLLVM_DragonFly: - return OsDragonFly; - case ZigLLVM_FreeBSD: - return OsFreeBSD; - case ZigLLVM_Fuchsia: - return OsFuchsia; - case ZigLLVM_IOS: - return OsIOS; - case ZigLLVM_KFreeBSD: - return OsKFreeBSD; - case ZigLLVM_Linux: - return OsLinux; - case ZigLLVM_Lv2: - return OsLv2; - case ZigLLVM_Darwin: - case ZigLLVM_MacOSX: - return OsMacOSX; - case ZigLLVM_NetBSD: - return OsNetBSD; - case ZigLLVM_OpenBSD: - return OsOpenBSD; - case ZigLLVM_Solaris: - return OsSolaris; - case ZigLLVM_Win32: - return OsWindows; - case ZigLLVM_ZOS: - return OsZOS; - case ZigLLVM_Haiku: - return OsHaiku; - case ZigLLVM_Minix: - return OsMinix; - case ZigLLVM_RTEMS: - return OsRTEMS; - case ZigLLVM_NaCl: - return OsNaCl; - case ZigLLVM_AIX: - return OsAIX; - case ZigLLVM_CUDA: - return OsCUDA; - case ZigLLVM_NVCL: - return OsNVCL; - case ZigLLVM_AMDHSA: - return OsAMDHSA; - case ZigLLVM_PS4: - return OsPS4; - case ZigLLVM_PS5: - return OsPS5; - case ZigLLVM_ELFIAMCU: - return OsELFIAMCU; - case ZigLLVM_TvOS: - return OsTvOS; - case ZigLLVM_WatchOS: - return OsWatchOS; - case ZigLLVM_Mesa3D: - return OsMesa3D; - case ZigLLVM_Contiki: - return OsContiki; - case ZigLLVM_AMDPAL: - return OsAMDPAL; - case ZigLLVM_HermitCore: - return OsHermitCore; - case ZigLLVM_Hurd: - return OsHurd; - case ZigLLVM_WASI: - return OsWASI; - case ZigLLVM_Emscripten: - return OsEmscripten; - case ZigLLVM_DriverKit: - return OsDriverKit; - case ZigLLVM_ShaderModel: - return OsShaderModel; - } - zig_unreachable(); -} - -static void get_native_target(ZigTarget *target) { - // first zero initialize - *target = {}; - - ZigLLVM_OSType os_type; - ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os - ZigLLVM_VendorType trash; - ZigLLVMGetNativeTarget( - &target->arch, - &trash, - &os_type, - &target->abi, - &oformat); - target->os = get_zig_os_type(os_type); - target->is_native_os = true; - target->is_native_cpu = true; - if (target->abi == ZigLLVM_UnknownEnvironment) { - target->abi = target_default_abi(target->arch, target->os); - } -} - -static const char* get_baseline_llvm_cpu_name(ZigLLVM_ArchType arch) { - return ""; -} - -static const char* get_baseline_llvm_cpu_features(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_riscv64: return "+a,+c,+d,+m"; - default: return ""; - } -} - -static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu, - const char *dynamic_linker) -{ - Error err; - - if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) { - zig_triple = nullptr; - } - - if (zig_triple == nullptr) { - get_native_target(target); - - if (mcpu == nullptr || strcmp(mcpu, "native") == 0) { - target->llvm_cpu_name = ZigLLVMGetHostCPUName(); - target->llvm_cpu_features = ZigLLVMGetNativeFeatures(); - } else if (strcmp(mcpu, "baseline") == 0) { - target->is_native_os = false; - target->is_native_cpu = false; - target->llvm_cpu_name = get_baseline_llvm_cpu_name(target->arch); - target->llvm_cpu_features = get_baseline_llvm_cpu_features(target->arch); - } else { - const char *msg = "stage0 can't handle CPU/features in the target"; - stage2_panic(msg, strlen(msg)); - } - } else { - // first initialize all to zero - *target = {}; - - SplitIterator it = memSplit(str(zig_triple), str("-")); - - Optional> opt_archsub = SplitIterator_next(&it); - Optional> opt_os = SplitIterator_next(&it); - Optional> opt_abi = SplitIterator_next(&it); - - if (!opt_archsub.is_some) - return ErrorMissingArchitecture; - - if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) { - return err; - } - - if (!opt_os.is_some) - return ErrorMissingOperatingSystem; - - if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) { - return err; - } - - if (opt_abi.is_some) { - if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) { - return err; - } - } else { - target->abi = target_default_abi(target->arch, target->os); - } - - if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) { - const char *msg = "stage0 can't handle CPU/features in the target"; - stage2_panic(msg, strlen(msg)); - } - - target->llvm_cpu_name = get_baseline_llvm_cpu_name(target->arch); - target->llvm_cpu_features = get_baseline_llvm_cpu_features(target->arch); - } - - return ErrorNone; -} - - -static bool str_starts_with(const char *s1, const char *s2) { - size_t s2_len = strlen(s2); - if (strlen(s1) < s2_len) { - return false; - } - return memcmp(s1, s2, s2_len) == 0; -} - -int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) { - if (root_progress_node != nullptr) { - stage2_progress_end(root_progress_node); - } - return exit_code; -} - -int main(int argc, char **argv) { - zig_stage1_os_init(); - - char *arg0 = argv[0]; - Error err; - - const char *in_file = nullptr; - const char *emit_bin_path = nullptr; - bool strip = false; - const char *out_name = nullptr; - bool verbose_ir = false; - bool verbose_llvm_ir = false; - bool verbose_cimport = false; - bool verbose_llvm_cpu_features = false; - ErrColor color = ErrColorAuto; - const char *dynamic_linker = nullptr; - bool link_libc = false; - bool link_libcpp = false; - const char *target_string = nullptr; - ZigStage1Pkg *cur_pkg = heap::c_allocator.create(); - BuildMode optimize_mode = BuildModeDebug; - TargetSubsystem subsystem = TargetSubsystemAuto; - const char *override_lib_dir = nullptr; - const char *mcpu = nullptr; - bool single_threaded = false; - bool is_test_build = false; - bool include_compiler_rt = false; - - for (int i = 1; i < argc; i += 1) { - char *arg = argv[i]; - - if (arg[0] == '-') { - if (strcmp(arg, "--") == 0) { - fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg); - } else if (strcmp(arg, "--test") == 0) { - is_test_build = true; - } else if (strcmp(arg, "-ODebug") == 0) { - optimize_mode = BuildModeDebug; - } else if (strcmp(arg, "-OReleaseFast") == 0) { - optimize_mode = BuildModeFastRelease; - } else if (strcmp(arg, "-OReleaseSafe") == 0) { - optimize_mode = BuildModeSafeRelease; - } else if (strcmp(arg, "-OReleaseSmall") == 0) { - optimize_mode = BuildModeSmallRelease; - } else if (strcmp(arg, "-fsingle-threaded") == 0) { - single_threaded = true; - } else if (strcmp(arg, "--help") == 0) { - return print_full_usage(arg0, stdout, EXIT_SUCCESS); - } else if (strcmp(arg, "--strip") == 0) { - strip = true; - } else if (strcmp(arg, "--verbose-ir") == 0) { - verbose_ir = true; - } else if (strcmp(arg, "--verbose-llvm-ir") == 0) { - verbose_llvm_ir = true; - } else if (strcmp(arg, "--verbose-cimport") == 0) { - verbose_cimport = true; - } else if (strcmp(arg, "--verbose-llvm-cpu-features") == 0) { - verbose_llvm_cpu_features = true; - } else if (arg[1] == 'l' && arg[2] != 0) { - // alias for --library - const char *l = &arg[2]; - if (strcmp(l, "c") == 0) { - link_libc = true; - } else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) { - link_libcpp = true; - } - } else if (strcmp(arg, "--pkg-begin") == 0) { - if (i + 2 >= argc) { - fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); - return print_error_usage(arg0); - } - ZigStage1Pkg *new_cur_pkg = heap::c_allocator.create(); - i += 1; - new_cur_pkg->name_ptr = argv[i]; - new_cur_pkg->name_len = strlen(argv[i]); - i += 1; - new_cur_pkg->path_ptr = argv[i]; - new_cur_pkg->path_len = strlen(argv[i]); - new_cur_pkg->parent = cur_pkg; - cur_pkg->children_ptr = heap::c_allocator.reallocate(cur_pkg->children_ptr, - cur_pkg->children_len, cur_pkg->children_len + 1); - cur_pkg->children_ptr[cur_pkg->children_len] = new_cur_pkg; - cur_pkg->children_len += 1; - - cur_pkg = new_cur_pkg; - } else if (strcmp(arg, "--pkg-end") == 0) { - if (cur_pkg->parent == nullptr) { - fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n"); - return EXIT_FAILURE; - } - cur_pkg = cur_pkg->parent; - } else if (str_starts_with(arg, "-mcpu=")) { - mcpu = arg + strlen("-mcpu="); - } else if (str_starts_with(arg, "-femit-bin=")) { - emit_bin_path = arg + strlen("-femit-bin="); - } else if (strcmp(arg, "-fcompiler-rt") == 0) { - include_compiler_rt = true; - } else if (i + 1 >= argc) { - fprintf(stderr, "Expected another argument after %s\n", arg); - return print_error_usage(arg0); - } else { - i += 1; - if (strcmp(arg, "--color") == 0) { - if (strcmp(argv[i], "auto") == 0) { - color = ErrColorAuto; - } else if (strcmp(argv[i], "on") == 0) { - color = ErrColorOn; - } else if (strcmp(argv[i], "off") == 0) { - color = ErrColorOff; - } else { - fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); - return print_error_usage(arg0); - } - } else if (strcmp(arg, "--name") == 0) { - out_name = argv[i]; - } else if (strcmp(arg, "--dynamic-linker") == 0) { - dynamic_linker = argv[i]; - } else if (strcmp(arg, "--zig-lib-dir") == 0) { - override_lib_dir = argv[i]; - } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) { - if (strcmp(argv[i], "c") == 0) { - link_libc = true; - } else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) { - link_libcpp = true; - } - } else if (strcmp(arg, "-target") == 0) { - target_string = argv[i]; - } else if (strcmp(arg, "--subsystem") == 0) { - if (strcmp(argv[i], "console") == 0) { - subsystem = TargetSubsystemConsole; - } else if (strcmp(argv[i], "windows") == 0) { - subsystem = TargetSubsystemWindows; - } else if (strcmp(argv[i], "posix") == 0) { - subsystem = TargetSubsystemPosix; - } else if (strcmp(argv[i], "native") == 0) { - subsystem = TargetSubsystemNative; - } else if (strcmp(argv[i], "efi_application") == 0) { - subsystem = TargetSubsystemEfiApplication; - } else if (strcmp(argv[i], "efi_boot_service_driver") == 0) { - subsystem = TargetSubsystemEfiBootServiceDriver; - } else if (strcmp(argv[i], "efi_rom") == 0) { - subsystem = TargetSubsystemEfiRom; - } else if (strcmp(argv[i], "efi_runtime_driver") == 0) { - subsystem = TargetSubsystemEfiRuntimeDriver; - } else { - fprintf(stderr, "invalid: --subsystem %s\n" - "Options are:\n" - " console\n" - " windows\n" - " posix\n" - " native\n" - " efi_application\n" - " efi_boot_service_driver\n" - " efi_rom\n" - " efi_runtime_driver\n" - , argv[i]); - return EXIT_FAILURE; - } - } else if (strcmp(arg, "-mcpu") == 0) { - mcpu = argv[i]; - } else { - fprintf(stderr, "Invalid argument: %s\n", arg); - return print_error_usage(arg0); - } - } - } else if (!in_file) { - in_file = arg; - } else { - fprintf(stderr, "Unexpected extra parameter: %s\n", arg); - return print_error_usage(arg0); - } - } - - if (cur_pkg->parent != nullptr) { - fprintf(stderr, "Unmatched --pkg-begin\n"); - return EXIT_FAILURE; - } - - Stage2Progress *progress = stage2_progress_create(); - Stage2ProgressNode *root_progress_node = stage2_progress_start_root(progress, "", 0, 0); - if (color == ErrColorOff) stage2_progress_disable_tty(progress); - - ZigTarget target; - if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) { - fprintf(stderr, "invalid target: %s\n", err_str(err)); - return print_error_usage(arg0); - } - - if (in_file == nullptr) { - fprintf(stderr, "missing zig file\n"); - return print_error_usage(arg0); - } - - if (out_name == nullptr) { - fprintf(stderr, "missing --name\n"); - return print_error_usage(arg0); - } - - if (override_lib_dir == nullptr) { - fprintf(stderr, "missing --zig-lib-dir\n"); - return print_error_usage(arg0); - } - - if (emit_bin_path == nullptr) { - fprintf(stderr, "missing -femit-bin=\n"); - return print_error_usage(arg0); - } - - ZigStage1 *stage1 = zig_stage1_create(optimize_mode, - nullptr, 0, - in_file, strlen(in_file), - override_lib_dir, strlen(override_lib_dir), - &target, is_test_build); - - stage1->main_progress_node = root_progress_node; - stage1->root_name_ptr = out_name; - stage1->root_name_len = strlen(out_name); - stage1->strip = strip; - stage1->verbose_ir = verbose_ir; - stage1->verbose_llvm_ir = verbose_llvm_ir; - stage1->verbose_cimport = verbose_cimport; - stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features; - stage1->emit_o_ptr = emit_bin_path; - stage1->emit_o_len = strlen(emit_bin_path); - stage1->main_pkg = cur_pkg; - stage1->err_color = color; - stage1->link_libc = link_libc; - stage1->link_libcpp = link_libcpp; - stage1->subsystem = subsystem; - stage1->pic = true; - stage1->is_single_threaded = single_threaded; - stage1->include_compiler_rt = include_compiler_rt; - - zig_stage1_build_object(stage1); - - zig_stage1_destroy(stage1); - - return main_exit(root_progress_node, EXIT_SUCCESS); -} - -void stage2_panic(const char *ptr, size_t len) { - fwrite(ptr, 1, len, stderr); - fprintf(stderr, "\n"); - fflush(stderr); - abort(); -} - -struct Stage2Progress { - int trash; -}; - -struct Stage2ProgressNode { - int trash; -}; - -Stage2Progress *stage2_progress_create(void) { - return nullptr; -} - -void stage2_progress_destroy(Stage2Progress *progress) {} - -Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -void stage2_progress_end(Stage2ProgressNode *node) {} -void stage2_progress_complete_one(Stage2ProgressNode *node) {} -void stage2_progress_disable_tty(Stage2Progress *progress) {} -void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} - -const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len, - size_t *result_len) -{ - Error err; - Buf contents_buf = BUF_INIT; - Buf path_buf = BUF_INIT; - - buf_init_from_mem(&path_buf, path_ptr, path_len); - if ((err = os_fetch_file_path(&path_buf, &contents_buf))) { - return nullptr; - } - *result_len = buf_len(&contents_buf); - return buf_ptr(&contents_buf); -} - -Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len, - const char **out_zig_path_ptr, size_t *out_zig_path_len, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len) -{ - const char *msg = "stage0 called stage2_cimport"; - stage2_panic(msg, strlen(msg)); -} - -const char *stage2_add_link_lib(struct ZigStage1 *stage1, - const char *lib_name_ptr, size_t lib_name_len, - const char *symbol_name_ptr, size_t symbol_name_len) -{ - return nullptr; -} - -const char *stage2_version_string(void) { - return ZIG_VERSION_STRING; -} - -struct Stage2SemVer stage2_version(void) { - return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH}; -} - -Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len) -{ - return ErrorNone; -} diff --git a/src/stage1/zigendian.h b/src/stage1/zigendian.h deleted file mode 100644 index 0a4f6a6ad2c3..000000000000 --- a/src/stage1/zigendian.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ZIG_ENDIAN_H -#define ZIG_ENDIAN_H - -// Every OSes seem to define endianness macros in different files. -#if defined(__APPLE__) - #include - #define ZIG_BIG_ENDIAN BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN LITTLE_ENDIAN - #define ZIG_BYTE_ORDER BYTE_ORDER -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #include - #define ZIG_BIG_ENDIAN _BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN _LITTLE_ENDIAN - #define ZIG_BYTE_ORDER _BYTE_ORDER -#elif defined(_WIN32) || defined(_WIN64) - // Assume that Windows installations are always little endian. - #define ZIG_LITTLE_ENDIAN 1 - #define ZIG_BYTE_ORDER ZIG_LITTLE_ENDIAN -#else // Linux - #include - #define ZIG_BIG_ENDIAN __BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN __LITTLE_ENDIAN - #define ZIG_BYTE_ORDER __BYTE_ORDER -#endif - -#if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - const bool native_is_big_endian = false; -#elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - const bool native_is_big_endian = true; -#else - #error Unsupported endian -#endif - -#endif // ZIG_ENDIAN_H From 0a2fdfbdb934faae7fcf63e9b3ab760c00f47918 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 13:42:34 -0700 Subject: [PATCH 05/68] build.zig: add bulk_memory to -Dwasi-bootstrap In theory this will enhance the performance of interpreting a WASI build of Zig. --- build.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/build.zig b/build.zig index 8560e5e2d2ca..675640ee1afb 100644 --- a/build.zig +++ b/build.zig @@ -22,6 +22,7 @@ pub fn build(b: *Builder) !void { if (wasi_bootstrap) { default_target.cpu_arch = .wasm32; default_target.os_tag = .wasi; + default_target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory)); break :t default_target; } else if (only_c) { default_target.ofmt = .c; From d5312d53a066092ba9efd687e25b29a87eb6290c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 13:50:44 -0700 Subject: [PATCH 06/68] WASI: remove absolute path emulation from std lib Instead of checking for absolute paths and current working directories in various file system operations, there is one simple solution: allow overriding `std.fs.cwd` on WASI. os.realpath is back to causing a compile error when used on WASI. This caused a compile error in the Sema handling of `@src()`. The compiler should never call realpath, so the commit that made this change is reverted (95ab942184427e7c9b840d71f4d093931e3e48fb). If this breaks debug info, a different strategy is needed to solve it other than using realpath. I also removed the preopens code and replaced it with something much simpler. There is no longer any global state in the standard library. Additionally- * os.openat no longer does an unnecessary fstat on WASI when O.WRONLY is not provided. * os.chdir is back to causing a compile error on WASI. --- lib/std/fs.zig | 35 ++--- lib/std/fs/wasi.zig | 311 ++++++-------------------------------------- lib/std/os.zig | 212 +++++------------------------- src/Sema.zig | 11 +- src/introspect.zig | 44 +------ src/main.zig | 85 ++++++++---- 6 files changed, 148 insertions(+), 550 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 12ee39a7bf43..2640abff1e8e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1130,13 +1130,6 @@ pub const Dir = struct { w.RIGHT.FD_FILESTAT_SET_TIMES | w.RIGHT.FD_FILESTAT_SET_SIZE; } - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - const fd = try os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, 0x0, 0x0, fdflags, base, 0x0); - return File{ .handle = fd }; - } const fd = try os.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0); return File{ .handle = fd }; } @@ -1301,13 +1294,6 @@ pub const Dir = struct { if (flags.exclusive) { oflags |= w.O.EXCL; } - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - const fd = try os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, 0x0, oflags, 0x0, base, 0x0); - return File{ .handle = fd }; - } const fd = try os.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0); return File{ .handle = fd }; } @@ -1711,16 +1697,15 @@ pub const Dir = struct { // TODO do we really need all the rights here? const inheriting: w.rights_t = w.RIGHT.ALL ^ w.RIGHT.SOCK_SHUTDOWN; - const result = blk: { - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - break :blk os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, symlink_flags, w.O.DIRECTORY, 0x0, base, inheriting); - } else { - break :blk os.openatWasi(self.fd, sub_path, symlink_flags, w.O.DIRECTORY, 0x0, base, inheriting); - } - }; + const result = os.openatWasi( + self.fd, + sub_path, + symlink_flags, + w.O.DIRECTORY, + 0x0, + base, + inheriting, + ); const fd = result catch |err| switch (err) { error.FileTooBig => unreachable, // can't happen for directories error.IsDir => unreachable, // we're providing O.DIRECTORY @@ -2667,6 +2652,8 @@ pub const Dir = struct { pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; + } else if (builtin.os.tag == .wasi and @hasDecl(root, "wasi_cwd")) { + return root.wasi_cwd(); } else { return Dir{ .fd = os.AT.FDCWD }; } diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 706cec905e9b..d15f37dc0fe7 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -10,284 +10,47 @@ const wasi = std.os.wasi; const fd_t = wasi.fd_t; const prestat_t = wasi.prestat_t; -/// Type-tag of WASI preopen. -/// -/// WASI currently offers only `Dir` as a valid preopen resource. -pub const PreopenTypeTag = enum { - Dir, -}; - -/// Type of WASI preopen. -/// -/// WASI currently offers only `Dir` as a valid preopen resource. -pub const PreopenType = union(PreopenTypeTag) { - /// Preopened directory type. - Dir: []const u8, - - const Self = @This(); - - pub fn eql(self: Self, other: PreopenType) bool { - if (std.meta.activeTag(self) != std.meta.activeTag(other)) return false; - - switch (self) { - PreopenTypeTag.Dir => |this_path| return mem.eql(u8, this_path, other.Dir), - } - } - - // Checks whether `other` refers to a subdirectory of `self` and, if so, - // returns the relative path to `other` from `self` - // - // Expects `other` to be a canonical path, not containing "." or ".." - pub fn getRelativePath(self: Self, other: PreopenType) ?[]const u8 { - if (std.meta.activeTag(self) != std.meta.activeTag(other)) return null; - - switch (self) { - PreopenTypeTag.Dir => |self_path| { - const other_path = other.Dir; - if (mem.indexOfDiff(u8, self_path, other_path)) |index| { - if (index < self_path.len) return null; - } - - const rel_path = other_path[self_path.len..]; - if (rel_path.len == 0) { - return rel_path; - } else if (rel_path[0] == '/') { - return rel_path[1..]; - } else { - if (self_path[self_path.len - 1] != '/') return null; - return rel_path; - } - }, - } - } - - pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); - _ = options; - try out_stream.print("PreopenType{{ ", .{}); - switch (self) { - PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{std.zig.fmtId(path)}), - } - return out_stream.print(" }}", .{}); - } -}; - -/// WASI preopen struct. This struct consists of a WASI file descriptor -/// and type of WASI preopen. It can be obtained directly from the WASI -/// runtime using `PreopenList.populate()` method. -pub const Preopen = struct { - /// WASI file descriptor. - fd: fd_t, - - /// Type of the preopen. - type: PreopenType, - - /// Construct new `Preopen` instance. - pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen { - return Preopen{ - .fd = fd, - .type = preopen_type, - }; - } -}; - -/// WASI resource identifier struct. This is effectively a path within -/// a WASI Preopen. -pub const PreopenUri = struct { - /// WASI Preopen containing the resource. - base: Preopen, - /// Path to resource within `base`. - relative_path: []const u8, -}; - -/// Dynamically-sized array list of WASI preopens. This struct is a -/// convenience wrapper for issuing `std.os.wasi.fd_prestat_get` and -/// `std.os.wasi.fd_prestat_dir_name` syscalls to the WASI runtime, and -/// collecting the returned preopens. -/// -/// This struct is intended to be used in any WASI program which intends -/// to use the capabilities as passed on by the user of the runtime. -pub const PreopenList = struct { - const InnerList = std.ArrayList(Preopen); - - /// Internal dynamically-sized buffer for storing the gathered preopens. - buffer: InnerList, - - const Self = @This(); - - pub const Error = error{ OutOfMemory, Overflow } || os.UnexpectedError; - - /// Deinitialize with `deinit`. - pub fn init(allocator: Allocator) Self { - return Self{ .buffer = InnerList.init(allocator) }; - } - - /// Release all allocated memory. - pub fn deinit(pm: Self) void { - for (pm.buffer.items) |preopen| { - switch (preopen.type) { - PreopenType.Dir => |path| pm.buffer.allocator.free(path), - } - } - pm.buffer.deinit(); - } - - /// Populate the list with the preopens by issuing `std.os.wasi.fd_prestat_get` - /// and `std.os.wasi.fd_prestat_dir_name` syscalls to the runtime. - /// - /// If called more than once, it will clear its contents every time before - /// issuing the syscalls. - /// - /// In the unlinkely event of overflowing the number of available file descriptors, - /// returns `error.Overflow`. In this case, even though an error condition was reached - /// the preopen list still contains all valid preopened file descriptors that are valid - /// for use. Therefore, it is fine to call `find`, `asSlice`, or `toOwnedSlice`. Finally, - /// `deinit` still must be called! - /// - /// Usage of `cwd_root`: - /// If provided, `cwd_root` is inserted as prefix for any Preopens that - /// begin with "." and all paths are normalized as POSIX-style absolute - /// paths. `cwd_root` must be an absolute path. - /// - /// For example: - /// "./foo/bar" -> "{cwd_root}/foo/bar" - /// "foo/bar" -> "/foo/bar" - /// "/foo/bar" -> "/foo/bar" - /// - /// If `cwd_root` is not provided, all preopen directories are unmodified. - /// - pub fn populate(self: *Self, cwd_root: ?[]const u8) Error!void { - if (cwd_root) |root| assert(fs.path.isAbsolute(root)); - - // Clear contents if we're being called again - for (try self.toOwnedSlice()) |preopen| { - switch (preopen.type) { - PreopenType.Dir => |path| self.buffer.allocator.free(path), - } - } - errdefer self.deinit(); - var fd: fd_t = 3; // start fd has to be beyond stdio fds - - var path_buf: [fs.MAX_PATH_BYTES]u8 = undefined; - while (true) { - var buf: prestat_t = undefined; - switch (wasi.fd_prestat_get(fd, &buf)) { - .SUCCESS => {}, - .OPNOTSUPP => { - // not a preopen, so keep going - fd = try math.add(fd_t, fd, 1); - continue; - }, - .BADF => { - // OK, no more fds available - break; - }, - else => |err| return os.unexpectedErrno(err), - } - const preopen_len = buf.u.dir.pr_name_len; - - mem.set(u8, path_buf[0..preopen_len], 0); - switch (wasi.fd_prestat_dir_name(fd, &path_buf, preopen_len)) { - .SUCCESS => {}, - else => |err| return os.unexpectedErrno(err), - } - - // Unfortunately, WASI runtimes (e.g. wasmer) are not consistent about whether the - // NULL sentinel is included in the reported Preopen name_len - const raw_path = if (path_buf[preopen_len - 1] == 0) blk: { - break :blk path_buf[0 .. preopen_len - 1]; - } else path_buf[0..preopen_len]; - - // If we were provided a CWD root to resolve against, we try to treat Preopen dirs as - // POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "." - const path = if (cwd_root) |cwd| blk: { - const resolve_paths: []const []const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path }; - break :blk try fs.path.resolve(self.buffer.allocator, resolve_paths); - } else blk: { - // If we were provided no CWD root, we preserve the preopen dir without resolving - break :blk try self.buffer.allocator.dupe(u8, raw_path); - }; - errdefer self.buffer.allocator.free(path); - const preopen = Preopen.new(fd, .{ .Dir = path }); - - try self.buffer.append(preopen); - fd = try math.add(fd_t, fd, 1); - } - } - - /// Find a preopen which includes access to `preopen_type`. - /// - /// If multiple preopens match the provided resource, the most specific - /// match is returned. More recent preopens take priority, as well. - pub fn findContaining(self: Self, preopen_type: PreopenType) ?PreopenUri { - var best_match: ?PreopenUri = null; - - for (self.buffer.items) |preopen| { - if (preopen.type.getRelativePath(preopen_type)) |rel_path| { - if (best_match == null or rel_path.len <= best_match.?.relative_path.len) { - best_match = PreopenUri{ - .base = preopen, - .relative_path = if (rel_path.len == 0) "." else rel_path, - }; - } - } - } - return best_match; - } - - /// Find preopen by fd. If the preopen exists, return it. - /// Otherwise, return `null`. - pub fn findByFd(self: Self, fd: fd_t) ?Preopen { - for (self.buffer.items) |preopen| { - if (preopen.fd == fd) { - return preopen; +pub const Preopens = struct { + // Indexed by file descriptor number. + names: []const []const u8, + + pub fn find(p: Preopens, name: []const u8) ?os.fd_t { + for (p.names) |elem_name, i| { + if (mem.eql(u8, elem_name, name)) { + return @intCast(os.fd_t, i); } } return null; } - - /// Find preopen by type. If the preopen exists, return it. - /// Otherwise, return `null`. - pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen { - for (self.buffer.items) |*preopen| { - if (preopen.type.eql(preopen_type)) { - return preopen; - } - } - return null; - } - - /// Return the inner buffer as read-only slice. - pub fn asSlice(self: Self) []const Preopen { - return self.buffer.items; - } - - /// The caller owns the returned memory. ArrayList becomes empty. - pub fn toOwnedSlice(self: *Self) ![]Preopen { - return try self.buffer.toOwnedSlice(); - } }; -test "extracting WASI preopens" { - if (builtin.os.tag != .wasi or builtin.link_libc) return error.SkipZigTest; - - var preopens = PreopenList.init(std.testing.allocator); - defer preopens.deinit(); - - try preopens.populate(null); - - const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable; - try std.testing.expect(preopen.type.eql(PreopenType{ .Dir = "." })); - - const po_type1 = PreopenType{ .Dir = "/" }; - try std.testing.expect(std.mem.eql(u8, po_type1.getRelativePath(.{ .Dir = "/" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type1.getRelativePath(.{ .Dir = "/test/foobar" }).?, "test/foobar")); - - const po_type2 = PreopenType{ .Dir = "/test/foo" }; - try std.testing.expect(po_type2.getRelativePath(.{ .Dir = "/test/foobar" }) == null); - - const po_type3 = PreopenType{ .Dir = "/test" }; - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test/" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test/foo/bar" }).?, "foo/bar")); +pub fn preopensAlloc(gpa: Allocator) Allocator.Error!Preopens { + var names: std.ArrayListUnmanaged([]const u8) = .{}; + defer names.deinit(gpa); + + try names.ensureUnusedCapacity(gpa, 3); + + names.appendAssumeCapacity("stdin"); // 0 + names.appendAssumeCapacity("stdout"); // 1 + names.appendAssumeCapacity("stderr"); // 2 + while (true) { + const fd = @intCast(wasi.fd_t, names.items.len); + var prestat: prestat_t = undefined; + switch (wasi.fd_prestat_get(fd, &prestat)) { + .SUCCESS => {}, + .OPNOTSUPP, .BADF => return .{ .names = names.toOwnedSlice(gpa) }, + else => @panic("fd_prestat_get: unexpected error"), + } + try names.ensureUnusedCapacity(gpa, 1); + // This length does not include a null byte. Let's keep it this way to + // gently encourage WASI implementations to behave properly. + const name_len = prestat.u.dir.pr_name_len; + const name = try gpa.alloc(u8, name_len); + errdefer gpa.free(name); + switch (wasi.fd_prestat_dir_name(fd, name.ptr, name.len)) { + .SUCCESS => {}, + else => @panic("fd_prestat_dir_name: unexpected error"), + } + names.appendAssumeCapacity(name); + } } diff --git a/lib/std/os.zig b/lib/std/os.zig index 7ebe41502695..ab43b3a0a17e 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1521,76 +1521,6 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t }; } -var wasi_cwd = if (builtin.os.tag == .wasi and !builtin.link_libc) struct { - // List of available Preopens - preopens: ?PreopenList = null, - // Memory buffer for storing the relative portion of the CWD - path_buffer: [MAX_PATH_BYTES]u8 = undefined, - // The absolute path associated with the current working directory - cwd: []const u8 = "/", -}{} else undefined; - -/// Initialize the available Preopen list on WASI and set the CWD to `cwd_init`. -/// Note that `cwd_init` corresponds to a Preopen directory, not necessarily -/// a POSIX path. For example, "." matches a Preopen provided with `--dir=.` -/// -/// This must be called before using any relative or absolute paths with `std.os` -/// functions, if you are on WASI without linking libc. -/// -/// The current working directory is initialized to `cwd_root`, and `cwd_root` -/// is inserted as a prefix for any Preopens whose dir begins with "." -/// For example: -/// "./foo/bar" - canonicalizes to -> "{cwd_root}/foo/bar" -/// "foo/bar" - canonicalizes to -> "/foo/bar" -/// "/foo/bar" - canonicalizes to -> "/foo/bar" -/// -/// `cwd_root` must be an absolute path. For initialization behavior similar to -/// wasi-libc, use "/" as the `cwd_root` -/// -/// `alloc` must not be a temporary or leak-detecting allocator, since `std.os` -/// retains ownership of allocations internally and may never call free(). -pub fn initPreopensWasi(alloc: Allocator, cwd_root: []const u8) !void { - if (builtin.os.tag == .wasi) { - if (!builtin.link_libc) { - var preopen_list = PreopenList.init(alloc); - errdefer preopen_list.deinit(); - try preopen_list.populate(cwd_root); - - var path_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer); - wasi_cwd.cwd = try path_alloc.allocator().dupe(u8, cwd_root); - - if (wasi_cwd.preopens) |preopens| preopens.deinit(); - wasi_cwd.preopens = preopen_list; - } else { - // wasi-libc defaults to an effective CWD root of "/" - if (!mem.eql(u8, cwd_root, "/")) return error.UnsupportedDirectory; - } - } -} - -/// Resolve a relative or absolute path to an handle (`fd_t`) and a relative subpath. -/// -/// For absolute paths, this automatically searches among available Preopens to find -/// a match. For relative paths, it uses the "emulated" CWD. -/// Automatically looks up the correct Preopen corresponding to the provided path. -pub fn resolvePathWasi(path: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) !RelativePathWasi { - var allocator = std.heap.FixedBufferAllocator.init(out_buffer); - var alloc = allocator.allocator(); - - const abs_path = fs.path.resolve(alloc, &.{ wasi_cwd.cwd, path }) catch return error.NameTooLong; - const preopen_uri = wasi_cwd.preopens.?.findContaining(.{ .Dir = abs_path }); - - if (preopen_uri) |po| { - return RelativePathWasi{ - .dir_fd = po.base.fd, - .relative_path = po.relative_path, - }; - } else { - // No matching preopen found - return error.AccessDenied; - } -} - /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openatZ`. @@ -1600,22 +1530,23 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope return openatW(dir_fd, file_path_w.span(), flags, mode); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { // `mode` is ignored on WASI, which does not support unix-style file permissions - const fd = if (dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) blk: { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(file_path, &path_buf); - - const opts = try openOptionsFromFlagsWasi(path.dir_fd, flags); - break :blk try openatWasi(path.dir_fd, path.relative_path, opts.lookup_flags, opts.oflags, opts.fs_flags, opts.fs_rights_base, opts.fs_rights_inheriting); - } else blk: { - const opts = try openOptionsFromFlagsWasi(dir_fd, flags); - break :blk try openatWasi(dir_fd, file_path, opts.lookup_flags, opts.oflags, opts.fs_flags, opts.fs_rights_base, opts.fs_rights_inheriting); - }; + const opts = try openOptionsFromFlagsWasi(dir_fd, flags); + const fd = try openatWasi( + dir_fd, + file_path, + opts.lookup_flags, + opts.oflags, + opts.fs_flags, + opts.fs_rights_base, + opts.fs_rights_inheriting, + ); errdefer close(fd); - const info = try fstat(fd); - if (flags & O.WRONLY != 0 and info.filetype == .DIRECTORY) - return error.IsDir; + if (flags & O.WRONLY != 0) { + const info = try fstat(fd); + if (info.filetype == .DIRECTORY) + return error.IsDir; + } return fd; } @@ -1673,7 +1604,15 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions { } /// Open and possibly create a file in WASI. -pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, lookup_flags: lookupflags_t, oflags: oflags_t, fdflags: fdflags_t, base: rights_t, inheriting: rights_t) OpenError!fd_t { +pub fn openatWasi( + dir_fd: fd_t, + file_path: []const u8, + lookup_flags: lookupflags_t, + oflags: oflags_t, + fdflags: fdflags_t, + base: rights_t, + inheriting: rights_t, +) OpenError!fd_t { while (true) { var fd: fd_t = undefined; switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) { @@ -2031,7 +1970,7 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { if (builtin.os.tag == .windows) { return windows.GetCurrentDirectory(out_buffer); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - const path = wasi_cwd.cwd; + const path = "."; if (out_buffer.len < path.len) return error.NameTooLong; std.mem.copy(u8, out_buffer, path); return out_buffer[0..path.len]; @@ -2125,12 +2064,6 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const if (builtin.os.tag == .windows) { @compileError("symlinkat is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (newdirfd == wasi.AT.FDCWD or fs.path.isAbsolute(target_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(sym_link_path, &path_buf); - return symlinkatWasi(target_path, path.dir_fd, path.relative_path); - } return symlinkatWasi(target_path, newdirfd, sym_link_path); } const target_path_c = try toPosixPath(target_path); @@ -2284,25 +2217,8 @@ pub fn linkat( flags: i32, ) LinkatError!void { if (builtin.os.tag == .wasi and !builtin.link_libc) { - var resolve_olddir: bool = (olddir == wasi.AT.FDCWD or fs.path.isAbsolute(oldpath)); - var resolve_newdir: bool = (newdir == wasi.AT.FDCWD or fs.path.isAbsolute(newpath)); - - var old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath }; - var new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath }; - - // Resolve absolute or CWD-relative paths to a path within a Preopen - if (resolve_olddir or resolve_newdir) { - var buf_old: [MAX_PATH_BYTES]u8 = undefined; - var buf_new: [MAX_PATH_BYTES]u8 = undefined; - - if (resolve_olddir) - old = try resolvePathWasi(oldpath, &buf_old); - - if (resolve_newdir) - new = try resolvePathWasi(newpath, &buf_new); - - return linkatWasi(old, new, flags); - } + const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath }; + const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath }; return linkatWasi(old, new, flags); } const old = try toPosixPath(oldpath); @@ -2423,12 +2339,6 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo const file_path_w = try windows.sliceToPrefixedFileW(file_path); return unlinkatW(dirfd, file_path_w.span(), flags); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(file_path, &path_buf); - return unlinkatWasi(path.dir_fd, path.relative_path, flags); - } return unlinkatWasi(dirfd, file_path, flags); } else { const file_path_c = try toPosixPath(file_path); @@ -2597,24 +2507,8 @@ pub fn renameat( const new_path_w = try windows.sliceToPrefixedFileW(new_path); return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - var resolve_old: bool = (old_dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(old_path)); - var resolve_new: bool = (new_dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(new_path)); - - var old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; - var new: RelativePathWasi = .{ .dir_fd = new_dir_fd, .relative_path = new_path }; - - // Resolve absolute or CWD-relative paths to a path within a Preopen - if (resolve_old or resolve_new) { - var buf_old: [MAX_PATH_BYTES]u8 = undefined; - var buf_new: [MAX_PATH_BYTES]u8 = undefined; - - if (resolve_old) - old = try resolvePathWasi(old_path, &buf_old); - if (resolve_new) - new = try resolvePathWasi(new_path, &buf_new); - - return renameatWasi(old, new); - } + const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; + const new: RelativePathWasi = .{ .dir_fd = new_dir_fd, .relative_path = new_path }; return renameatWasi(old, new); } else { const old_path_c = try toPosixPath(old_path); @@ -2755,12 +2649,6 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path); return mkdiratW(dir_fd, sub_dir_path_w.span(), mode); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(sub_dir_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(sub_dir_path, &path_buf); - return mkdiratWasi(path.dir_fd, path.relative_path, mode); - } return mkdiratWasi(dir_fd, sub_dir_path, mode); } else { const sub_dir_path_c = try toPosixPath(sub_dir_path); @@ -2997,22 +2885,7 @@ pub const ChangeCurDirError = error{ /// `dir_path` is recommended to be a UTF-8 encoded string. pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { if (builtin.os.tag == .wasi and !builtin.link_libc) { - var buf: [MAX_PATH_BYTES]u8 = undefined; - var alloc = std.heap.FixedBufferAllocator.init(&buf); - const path = fs.path.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path }) catch |err| switch (err) { - error.OutOfMemory => return error.NameTooLong, - else => |e| return e, - }; - - const dirinfo = try fstatat(AT.FDCWD, path, 0); - if (dirinfo.filetype != .DIRECTORY) { - return error.NotDir; - } - - // This copy is guaranteed to succeed, since buf and path_buffer are the same size. - var cwd_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer); - wasi_cwd.cwd = cwd_alloc.allocator().dupe(u8, path) catch unreachable; - return; + @compileError("WASI does not support os.chdir"); } else if (builtin.os.tag == .windows) { var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; const len = try std.unicode.utf8ToUtf16Le(utf16_dir_path[0..], dir_path); @@ -3143,12 +3016,6 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 /// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`. pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - var path = try resolvePathWasi(file_path, &path_buf); - return readlinkatWasi(path.dir_fd, path.relative_path, out_buffer); - } return readlinkatWasi(dirfd, file_path, out_buffer); } if (builtin.os.tag == .windows) { @@ -4155,12 +4022,6 @@ pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLink pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat { if (builtin.os.tag == .wasi and !builtin.link_libc) { const wasi_flags = if (flags & linux.AT.SYMLINK_NOFOLLOW == 0) wasi.LOOKUP_SYMLINK_FOLLOW else 0; - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(pathname)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(pathname, &path_buf); - return fstatatWasi(path.dir_fd, path.relative_path, wasi_flags); - } return fstatatWasi(dirfd, pathname, wasi_flags); } else if (builtin.os.tag == .windows) { @compileError("fstatat is not yet implemented on Windows"); @@ -4556,12 +4417,6 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path }; const file = blk: { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - resolved = resolvePathWasi(path, &path_buf) catch |err| break :blk @as(FStatAtError!Stat, err); - break :blk fstatat(resolved.dir_fd, resolved.relative_path, flags); - } break :blk fstatat(dirfd, path, flags); } catch |err| switch (err) { error.AccessDenied => return error.PermissionDenied, @@ -5147,12 +5002,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE const pathname_w = try windows.sliceToPrefixedFileW(pathname); return realpathW(pathname_w.span(), out_buffer); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - var alloc = std.heap.FixedBufferAllocator.init(out_buffer); - - // NOTE: This emulation is incomplete. Symbolic links are not - // currently expanded during path canonicalization. - const paths = &.{ wasi_cwd.cwd, pathname }; - return fs.path.resolve(alloc.allocator(), paths) catch error.NameTooLong; + @compileError("WASI does not support os.realpath"); } const pathname_c = try toPosixPath(pathname); return realpathZ(&pathname_c, out_buffer); diff --git a/src/Sema.zig b/src/Sema.zig index a85c80826edc..cb6165f2f689 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -15082,14 +15082,11 @@ fn zirBuiltinSrc( const file_name_val = blk: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); - const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena); - const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| { - return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) }); - }; - const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path); + // The compiler must not call realpath anywhere. + const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena()); const new_decl = try anon_decl.finish( - try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len), - try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]), + try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len), + try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]), 0, // default alignment ); break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); diff --git a/src/introspect.zig b/src/introspect.zig index 27925ab667a6..2eeae956ec91 100644 --- a/src/introspect.zig +++ b/src/introspect.zig @@ -37,34 +37,7 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory { /// based on a hard-coded Preopen directory ("/zig") pub fn findZigExePath(allocator: mem.Allocator) ![]u8 { if (builtin.os.tag == .wasi) { - var args = try std.process.argsWithAllocator(allocator); - defer args.deinit(); - // On WASI, argv[0] is always just the basename of the current executable - const argv0 = args.next() orelse return error.FileNotFound; - - // Check these paths: - // 1. "/zig/{exe_name}" - // 2. "/zig/bin/{exe_name}" - const base_paths_to_check = &[_][]const u8{ "/zig", "/zig/bin" }; - const exe_names_to_check = &[_][]const u8{ fs.path.basename(argv0), "zig.wasm" }; - - for (base_paths_to_check) |base_path| { - for (exe_names_to_check) |exe_name| { - const test_path = fs.path.join(allocator, &.{ base_path, exe_name }) catch continue; - defer allocator.free(test_path); - - // Make sure it's a file we're pointing to - const file = os.fstatat(os.wasi.AT.FDCWD, test_path, 0) catch continue; - if (file.filetype != .REGULAR_FILE) continue; - - // Path seems to be valid, let's try to turn it into an absolute path - var real_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined; - if (os.realpath(test_path, &real_path_buf)) |real_path| { - return allocator.dupe(u8, real_path); // Success: return absolute path - } else |_| continue; - } - } - return error.FileNotFound; + @compileError("this function is unsupported on WASI"); } return fs.selfExePathAlloc(allocator); @@ -107,6 +80,9 @@ pub fn findZigLibDirFromSelfExe( /// Caller owns returned memory. pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { + if (builtin.os.tag == .wasi) { + @compileError("on WASI the global cache dir must be resolved with preopens"); + } if (std.process.getEnvVarOwned(allocator, "ZIG_GLOBAL_CACHE_DIR")) |value| { if (value.len > 0) { return value; @@ -125,17 +101,7 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { } } - if (builtin.os.tag == .wasi) { - // On WASI, we have no way to get an App data dir, so we try to use a fixed - // Preopen path "/cache" as a last resort - const path = "/cache"; - - const file = os.fstatat(os.wasi.AT.FDCWD, path, 0) catch return error.CacheDirUnavailable; - if (file.filetype != .DIRECTORY) return error.CacheDirUnavailable; - return allocator.dupe(u8, path); - } else { - return fs.getAppDataDir(allocator, appname); - } + return fs.getAppDataDir(allocator, appname); } /// Similar to std.fs.path.resolve, with a few important differences: diff --git a/src/main.zig b/src/main.zig index 5947ff773aa4..11eaff905890 100644 --- a/src/main.zig +++ b/src/main.zig @@ -27,6 +27,23 @@ const crash_report = @import("crash_report.zig"); // Crash report needs to override the panic handler and other root decls pub usingnamespace crash_report.root_decls; +var wasi_preopens: fs.wasi.Preopens = undefined; +pub inline fn wasi_cwd() fs.Dir { + // Expect the first preopen to be current working directory. + const cwd_fd: std.os.fd_t = 3; + assert(mem.eql(u8, wasi_preopens.names[cwd_fd], ".")); + return .{ .fd = cwd_fd }; +} + +pub fn getWasiPreopen(name: []const u8) Compilation.Directory { + return .{ + .path = name, + .handle = .{ + .fd = wasi_preopens.find(name) orelse fatal("WASI preopen not found: '{s}'", .{name}), + }, + }; +} + pub fn fatal(comptime format: []const u8, args: anytype) noreturn { std.log.err(format, args); process.exit(1); @@ -161,20 +178,14 @@ pub fn main() anyerror!void { return mainArgs(gpa_tracy.allocator(), arena, args); } - // WASI: `--dir` instructs the WASM runtime to "preopen" a directory, making - // it available to the us, the guest program. This is the only way for us to - // access files/dirs on the host filesystem if (builtin.os.tag == .wasi) { - // This sets our CWD to "/preopens/cwd" - // Dot-prefixed preopens like `--dir=.` are "mounted" at "/preopens/cwd" - // Other preopens like `--dir=lib` are "mounted" at "/" - try std.os.initPreopensWasi(arena, "/preopens/cwd"); + wasi_preopens = try fs.wasi.preopensAlloc(arena); } // Short circuit some of the other logic for bootstrapping. if (build_options.only_c) { - assert(mem.eql(u8, args[1], "build-obj")); - return buildOutputType(gpa, arena, args, .{ .build = .Obj }); + assert(mem.eql(u8, args[1], "build-exe")); + return buildOutputType(gpa, arena, args, .{ .build = .Exe }); } return mainArgs(gpa, arena, args); @@ -2300,7 +2311,7 @@ fn buildOutputType( }, } - if (std.fs.path.isAbsolute(lib_name)) { + if (fs.path.isAbsolute(lib_name)) { fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } @@ -2763,18 +2774,33 @@ fn buildOutputType( } } - const self_exe_path = try introspect.findZigExePath(arena); - var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |unresolved_lib_dir| l: { - const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); - break :l .{ - .path = lib_dir, - .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { - fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); - }, + const self_exe_path: ?[]const u8 = if (!process.can_spawn) + null + else + introspect.findZigExePath(arena) catch |err| { + fatal("unable to find zig self exe path: {s}", .{@errorName(err)}); }; - } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| { - fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)}); + + var zig_lib_directory: Compilation.Directory = d: { + if (override_lib_dir) |unresolved_lib_dir| { + const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); + break :d .{ + .path = lib_dir, + .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { + fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); + }, + }; + } else if (builtin.os.tag == .wasi) { + break :d getWasiPreopen("/lib"); + } else if (self_exe_path) |p| { + break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| { + fatal("unable to find zig installation directory: {s}", .{@errorName(err)}); + }; + } else { + unreachable; + } }; + defer zig_lib_directory.handle.close(); var thread_pool: ThreadPool = undefined; @@ -2791,7 +2817,16 @@ fn buildOutputType( } var global_cache_directory: Compilation.Directory = l: { - const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena); + if (override_global_cache_dir) |p| { + break :l .{ + .handle = try fs.cwd().makeOpenPath(p, .{}), + .path = p, + }; + } + if (builtin.os.tag == .wasi) { + break :l getWasiPreopen("/cache"); + } + const p = try introspect.resolveGlobalCacheDir(arena); break :l .{ .handle = try fs.cwd().makeOpenPath(p, .{}), .path = p, @@ -3082,7 +3117,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3154,7 +3189,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3179,7 +3214,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3523,7 +3558,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void defer tree.deinit(comp.gpa); if (out_dep_path) |dep_file_path| { - const dep_basename = std.fs.path.basename(dep_file_path); + const dep_basename = fs.path.basename(dep_file_path); // Add the files depended on to the cache system. try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); // Just to save disk space, we delete the file because it is never needed again. From 3a8117439dce10a92e3c37a7dbf5440a9730ad41 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 14:00:16 -0700 Subject: [PATCH 07/68] allow `build-obj` and `build-exe` in -Donly-c builds --- src/main.zig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.zig b/src/main.zig index 11eaff905890..784cf3b29cb5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -184,8 +184,13 @@ pub fn main() anyerror!void { // Short circuit some of the other logic for bootstrapping. if (build_options.only_c) { - assert(mem.eql(u8, args[1], "build-exe")); - return buildOutputType(gpa, arena, args, .{ .build = .Exe }); + if (mem.eql(u8, args[1], "build-exe")) { + return buildOutputType(gpa, arena, args, .{ .build = .Exe }); + } else if (mem.eql(u8, args[1], "build-obj")) { + return buildOutputType(gpa, arena, args, .{ .build = .Obj }); + } else { + @panic("only build-exe or build-obj is supported in a -Donly-c build"); + } } return mainArgs(gpa, arena, args); From 6b0d77326678d198550c0cc3ef7fe82a53e0e508 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 14:00:55 -0700 Subject: [PATCH 08/68] std: clean up imports in a couple files --- lib/std/process.zig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/std/process.zig b/lib/std/process.zig index 22f5cc382eb4..23fad9e8c67d 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -355,7 +355,7 @@ pub const GetEnvVarOwnedError = error{ }; /// Caller must free returned memory. -pub fn getEnvVarOwned(allocator: mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { +pub fn getEnvVarOwned(allocator: Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { if (builtin.os.tag == .windows) { const result_w = blk: { const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); @@ -430,7 +430,7 @@ pub const ArgIteratorPosix = struct { }; pub const ArgIteratorWasi = struct { - allocator: mem.Allocator, + allocator: Allocator, index: usize, args: [][:0]u8, @@ -438,7 +438,7 @@ pub const ArgIteratorWasi = struct { /// You must call deinit to free the internal buffer of the /// iterator after you are done. - pub fn init(allocator: mem.Allocator) InitError!ArgIteratorWasi { + pub fn init(allocator: Allocator) InitError!ArgIteratorWasi { const fetched_args = try ArgIteratorWasi.internalInit(allocator); return ArgIteratorWasi{ .allocator = allocator, @@ -447,7 +447,7 @@ pub const ArgIteratorWasi = struct { }; } - fn internalInit(allocator: mem.Allocator) InitError![][:0]u8 { + fn internalInit(allocator: Allocator) InitError![][:0]u8 { const w = os.wasi; var count: usize = undefined; var buf_size: usize = undefined; @@ -760,7 +760,7 @@ pub const ArgIterator = struct { }; /// You must deinitialize iterator's internal buffers by calling `deinit` when done. - pub fn initWithAllocator(allocator: mem.Allocator) InitError!ArgIterator { + pub fn initWithAllocator(allocator: Allocator) InitError!ArgIterator { if (builtin.os.tag == .wasi and !builtin.link_libc) { return ArgIterator{ .inner = try InnerType.init(allocator) }; } @@ -804,7 +804,7 @@ pub fn args() ArgIterator { } /// You must deinitialize iterator's internal buffers by calling `deinit` when done. -pub fn argsWithAllocator(allocator: mem.Allocator) ArgIterator.InitError!ArgIterator { +pub fn argsWithAllocator(allocator: Allocator) ArgIterator.InitError!ArgIterator { return ArgIterator.initWithAllocator(allocator); } @@ -827,7 +827,7 @@ test "args iterator" { } /// Caller must call argsFree on result. -pub fn argsAlloc(allocator: mem.Allocator) ![][:0]u8 { +pub fn argsAlloc(allocator: Allocator) ![][:0]u8 { // TODO refactor to only make 1 allocation. var it = try argsWithAllocator(allocator); defer it.deinit(); @@ -864,7 +864,7 @@ pub fn argsAlloc(allocator: mem.Allocator) ![][:0]u8 { return result_slice_list; } -pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void { +pub fn argsFree(allocator: Allocator, args_alloc: []const [:0]u8) void { var total_bytes: usize = 0; for (args_alloc) |arg| { total_bytes += @sizeOf([]u8) + arg.len + 1; @@ -1089,7 +1089,7 @@ pub const ExecvError = std.os.ExecveError || error{OutOfMemory}; /// This function also uses the PATH environment variable to get the full path to the executable. /// Due to the heap-allocation, it is illegal to call this function in a fork() child. /// For that use case, use the `std.os` functions directly. -pub fn execv(allocator: mem.Allocator, argv: []const []const u8) ExecvError { +pub fn execv(allocator: Allocator, argv: []const []const u8) ExecvError { return execve(allocator, argv, null); } @@ -1102,7 +1102,7 @@ pub fn execv(allocator: mem.Allocator, argv: []const []const u8) ExecvError { /// Due to the heap-allocation, it is illegal to call this function in a fork() child. /// For that use case, use the `std.os` functions directly. pub fn execve( - allocator: mem.Allocator, + allocator: Allocator, argv: []const []const u8, env_map: ?*const EnvMap, ) ExecvError { From 55ca43a04c6273d3b68c4b5a40f8576c106de5e7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 14:01:13 -0700 Subject: [PATCH 09/68] std.wasm: add Opcode.prefixed and make PrefixedOpcode nonexhaustive --- lib/std/wasm.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig index 3d47d43487c4..12026f185839 100644 --- a/lib/std/wasm.zig +++ b/lib/std/wasm.zig @@ -188,6 +188,8 @@ pub const Opcode = enum(u8) { i64_extend8_s = 0xC2, i64_extend16_s = 0xC3, i64_extend32_s = 0xC4, + + prefixed = 0xFC, _, }; @@ -232,6 +234,7 @@ pub const PrefixedOpcode = enum(u8) { table_grow = 0x0F, table_size = 0x10, table_fill = 0x11, + _, }; /// Enum representing all Wasm value types as per spec: From 3dcdd5544faf9891e2e20391f4da2b42381f79ba Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Nov 2022 14:01:47 -0700 Subject: [PATCH 10/68] stage2: make --color override apply to std.Progress --- src/Compilation.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index e3c45678e2b1..42b64f979f96 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2380,7 +2380,16 @@ pub fn update(comp: *Compilation) !void { var progress: std.Progress = .{ .dont_print_on_dumb = true }; const main_progress_node = progress.start("", 0); defer main_progress_node.end(); - if (comp.color == .off) progress.terminal = null; + switch (comp.color) { + .off => { + progress.terminal = null; + }, + .on => { + progress.terminal = std.io.getStdErr(); + progress.supports_ansi_escape_codes = true; + }, + .auto => {}, + } try comp.performAllTheWork(main_progress_node); From 8c1c67bdd0a636006e7ddbc14da8c2484b131df7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 11 Nov 2022 22:59:39 -0700 Subject: [PATCH 11/68] stage2: take advantage of the new WasmAllocator --- src/main.zig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index 784cf3b29cb5..c8ac670d10d1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -152,8 +152,14 @@ var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{ pub fn main() anyerror!void { crash_report.initialize(); - const use_gpa = build_options.force_gpa or !builtin.link_libc; + const use_gpa = (build_options.force_gpa or !builtin.link_libc) and builtin.os.tag != .wasi; const gpa = gpa: { + if (builtin.os.tag == .wasi) { + break :gpa Allocator{ + .ptr = undefined, + .vtable = &std.heap.WasmAllocator.vtable, + }; + } if (use_gpa) { break :gpa general_purpose_allocator.allocator(); } From ef447c3ecac4211a0a03f487e84acc61160d7ede Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 00:33:05 -0700 Subject: [PATCH 12/68] redo CMakeLists.txt to use WASI interpreter current status is that it hits error: OutOfMemory for unknown reasons, probably due to bugs in the C WASI interpreter port. --- CMakeLists.txt | 492 +--- stage1/config.h.in | 30 + {src => stage1}/config.zig.in | 8 +- stage1/zig1.c | 4220 +++++++++++++++++++++++++++++++++ 4 files changed, 4331 insertions(+), 419 deletions(-) create mode 100644 stage1/config.h.in rename {src => stage1}/config.zig.in (72%) create mode 100755 stage1/zig1.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e289a79348c3..b9fd5614bcb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,5 @@ cmake_minimum_required(VERSION 2.8.12) -# Use ccache if possible -FIND_PROGRAM(CCACHE_PROGRAM ccache) -IF(CCACHE_PROGRAM) - MESSAGE(STATUS "Found ccache ${CCACHE_PROGRAM}") -ENDIF() - if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) @@ -98,10 +92,15 @@ set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib") set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd") -set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache if available") +set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache") -if(CCACHE_PROGRAM AND ZIG_USE_CCACHE) - SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") +if(ZIG_USE_CCACHE) + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") + else() + message(SEND_ERROR "ccache requested but not found") + endif() endif() if(ZIG_STATIC) @@ -118,19 +117,9 @@ string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_ string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}") string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_INCLUDE_DIR_ESCAPED "${ZIG_LIBC_INCLUDE_DIR}") -option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) - set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") set(ZIG_TARGET_MCPU "native" CACHE STRING "-mcpu parameter to output binaries for") -set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") -set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") - -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(ZIG_ENABLE_LOGGING ON CACHE BOOL "enable logging") -else() - set(ZIG_ENABLE_LOGGING OFF CACHE BOOL "enable logging") -endif() if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") set(ZIG_USE_LLVM_CONFIG ON CACHE BOOL "use llvm-config to find LLVM libraries") @@ -179,190 +168,6 @@ include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLD_INCLUDE_DIRS}) include_directories(${CLANG_INCLUDE_DIRS}) -# No patches have been applied to SoftFloat-3e -set(EMBEDDED_SOFTFLOAT_SOURCES - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_eq_signaling.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_le.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_le_quiet.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_lt_quiet.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_le.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/i32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip32_1.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare96M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros8.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_eq128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_isNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_le128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_lt128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mul128MTo256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mul64To128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_negXM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normExtF80SigM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_remStepMBy32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToUI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToI32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToUI32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToUI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftLeftM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJamM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftLeftM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_sub1XM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_sub256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_extF80M.c" -) -add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES}) -if(MSVC) - set(SOFTFLOAT_CFLAGS "/w") - - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(SOFTFLOAT_CFLAGS "${SOFTFLOAT_CFLAGS} /O2") - endif() - - set_target_properties(embedded_softfloat PROPERTIES - COMPILE_FLAGS ${SOFTFLOAT_CFLAGS} - ) -else() - set_target_properties(embedded_softfloat PROPERTIES - COMPILE_FLAGS "-std=c99 -O3" - ) -endif() -target_include_directories(embedded_softfloat PUBLIC - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e-prebuilt" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086" -) -include_directories("${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/include") -set(SOFTFLOAT_LIBRARIES embedded_softfloat) - find_package(Threads) set(ZIG_LIB_DIR "lib/zig") @@ -374,35 +179,8 @@ set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std") set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h") set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") -# This is our shim which will be replaced by stage1.zig. -set(ZIG1_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp" -) - set(STAGE1_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/analyze.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/astgen.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/bigfloat.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/bigint.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/buffer.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/codegen.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/errmsg.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/error.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/heap.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/ir.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/ir_print.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/mem.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/os.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/parser.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/range_set.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/softfloat_ext.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/stage1.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/target.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/tokenizer.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/util.cpp" -) -set(OPTIMIZED_C_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/parse_f128.c" + "${CMAKE_SOURCE_DIR}/stage1/zig1.c" ) set(ZIG_CPP_SOURCES # These are planned to stay even when we are self-hosted. @@ -416,11 +194,7 @@ set(ZIG_CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" ) # Needed because we use cmake, not the zig build system, to build zig2.o. -# This list is generated by building zig and then clearing the zig-cache directory, -# then manually running the build-obj command (see BUILD_ZIG2_ARGS), and then looking -# in the zig-cache directory for the compiler-generated list of zig file dependencies. set(ZIG_STAGE2_SOURCES - "${ZIG_CONFIG_ZIG_OUT}" "${CMAKE_SOURCE_DIR}/lib/std/array_hash_map.zig" "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig" "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig" @@ -828,7 +602,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/print_targets.zig" "${CMAKE_SOURCE_DIR}/src/print_zir.zig" "${CMAKE_SOURCE_DIR}/src/register_manager.zig" - "${CMAKE_SOURCE_DIR}/src/stage1.zig" "${CMAKE_SOURCE_DIR}/src/target.zig" "${CMAKE_SOURCE_DIR}/src/tracy.zig" "${CMAKE_SOURCE_DIR}/src/translate_c.zig" @@ -847,24 +620,12 @@ if(MSVC) endif() endif() -if(ZIG_OMIT_STAGE2) - set(ZIG_OMIT_STAGE2_BOOL "true") -else() - set(ZIG_OMIT_STAGE2_BOOL "false") -endif() - -if(ZIG_ENABLE_LOGGING) - set(ZIG_ENABLE_LOGGING_BOOL "true") -else() - set(ZIG_ENABLE_LOGGING_BOOL "false") -endif() - configure_file ( - "${CMAKE_SOURCE_DIR}/src/stage1/config.h.in" + "${CMAKE_SOURCE_DIR}/stage1/config.h.in" "${ZIG_CONFIG_H_OUT}" ) configure_file ( - "${CMAKE_SOURCE_DIR}/src/config.zig.in" + "${CMAKE_SOURCE_DIR}/stage1/config.zig.in" "${ZIG_CONFIG_ZIG_OUT}" ) @@ -872,55 +633,40 @@ include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} "${CMAKE_SOURCE_DIR}/src" - "${CMAKE_SOURCE_DIR}/src/stage1" ) # These have to go before the -Wno- flags if(MSVC) - set(EXE_CFLAGS "/std:c++14") + set(EXE_CXX_FLAGS "/std:c++14") else(MSVC) - set(EXE_CFLAGS "-std=c++14") + set(EXE_CXX_FLAGS "-std=c++14") endif(MSVC) -if(ZIG_STATIC) - set(EXE_CFLAGS "${EXE_CFLAGS} -DZIG_LINK_MODE=Static") -else() - set(EXE_CFLAGS "${EXE_CFLAGS} -DZIG_LINK_MODE=Dynamic") -endif() - if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if(MSVC) - set(EXE_CFLAGS "${EXE_CFLAGS} /w") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} /w") else() - set(EXE_CFLAGS "${EXE_CFLAGS} -Werror -Wall") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror -Wall") # fallthrough support was added in GCC 7.0 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) - set(EXE_CFLAGS "${EXE_CFLAGS} -Werror=implicit-fallthrough") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror=implicit-fallthrough") endif() # GCC 9.2 and older are unable to detect valid variable initialization in some cases if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 9.2) - set(EXE_CFLAGS "${EXE_CFLAGS} -Wno-maybe-uninitialized") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-maybe-uninitialized") endif() endif() endif() if(MSVC) - set(EXE_CFLAGS "${EXE_CFLAGS}") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS}") else() - set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") if(MINGW) - set(EXE_CFLAGS "${EXE_CFLAGS} -Wno-format") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-format") endif() endif() -if(MSVC) - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(OPTIMIZED_C_FLAGS "/O2") - endif() -else(MSVC) - set(OPTIMIZED_C_FLAGS "-std=c99 -O3") -endif(MSVC) - set(EXE_LDFLAGS " ") if(MSVC) set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216") @@ -939,21 +685,10 @@ if(ZIG_STATIC) elseif(NOT MSVC) set(EXE_LDFLAGS "${EXE_LDFLAGS} -static") endif() -else() - if(MINGW) - set(EXE_LDFLAGS "${EXE_LDFLAGS}") - endif() -endif() - -if(ZIG_TEST_COVERAGE) - set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage") - set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage") endif() add_library(zigcpp STATIC ${ZIG_CPP_SOURCES}) -set_target_properties(zigcpp PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} -) +set_target_properties(zigcpp PROPERTIES COMPILE_FLAGS ${EXE_CXX_FLAGS}) target_link_libraries(zigcpp LINK_PUBLIC ${CLANG_LIBRARIES} @@ -962,146 +697,73 @@ target_link_libraries(zigcpp LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} ) -add_library(opt_c_util STATIC ${OPTIMIZED_C_SOURCES}) -set_target_properties(opt_c_util PROPERTIES - COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}" -) -target_include_directories(opt_c_util PRIVATE - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e-prebuilt" -) - -add_library(zigstage1 STATIC ${STAGE1_SOURCES}) -set_target_properties(zigstage1 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} -) -target_link_libraries(zigstage1 LINK_PUBLIC - opt_c_util - ${SOFTFLOAT_LIBRARIES} - zigcpp -) -if(NOT MSVC) - target_link_libraries(zigstage1 LINK_PUBLIC ${LIBXML2}) -endif() - -if(ZIG_DIA_GUIDS_LIB) - target_link_libraries(zigstage1 LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) -endif() - -if(MSVC OR MINGW) - target_link_libraries(zigstage1 LINK_PUBLIC version) -endif() - -if("${ZIG_EXECUTABLE}" STREQUAL "") - add_executable(zig1 ${ZIG1_SOURCES}) - set_target_properties(zig1 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} - ) - target_link_libraries(zig1 zigstage1) -endif() - if(MSVC) - set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.obj") -else() - set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.o") -endif() -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(ZIG_RELEASE_ARG "") -elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") - set(ZIG_RELEASE_ARG -Drelease) -else() - set(ZIG_RELEASE_ARG -Drelease -Dstrip) -endif() -if(ZIG_NO_LIB) - set(ZIG_NO_LIB_ARG "-Dno-lib") + set(ZIG1_COMPILE_FLAGS "/std:c99") + set(ZIG2_COMPILE_FLAGS "/std:c99") + set(ZIG2_LINK_FLAGS "/STACK:16777216") else() - set(ZIG_NO_LIB_ARG "") -endif() -if(ZIG_SINGLE_THREADED) - set(ZIG_SINGLE_THREADED_ARG "-fsingle-threaded") -else() - set(ZIG_SINGLE_THREADED_ARG "") -endif() -if(ZIG_STATIC) - set(ZIG_STATIC_ARG "-Duse-zig-libcxx") -else() - set(ZIG_STATIC_ARG "") + #set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native") + set(ZIG1_COMPILE_FLAGS "-std=c99 -march=native") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O2 -march=native") + set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() +add_executable(zig1 ${STAGE1_SOURCES}) +set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) +#target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/lib") +target_link_libraries(zig1 LINK_PUBLIC m) + + +set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") set(BUILD_ZIG2_ARGS - "src/stage1.zig" - --name zig2 - --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" - "-femit-bin=${ZIG2_OBJECT}" - -fcompiler-rt - ${ZIG_SINGLE_THREADED_ARG} - -target native - -mcpu native - -lc - --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" - --pkg-end + "${CMAKE_SOURCE_DIR}/lib" + "${CMAKE_BINARY_DIR}/zig1-cache" + "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" + build-exe src/main.zig -ofmt=c -lc + --name zig2 + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" + --pkg-end + -target x86_64-linux-musl # TODO: autodetect in zig1.c + --color on # TODO: autodetect in zig1.c + -OReleaseFast +) + +add_custom_command( + OUTPUT "${ZIG2_C_SOURCE}" + COMMAND zig1 ${BUILD_ZIG2_ARGS} + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG2_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) -if("${ZIG_EXECUTABLE}" STREQUAL "") - add_custom_command( - OUTPUT "${ZIG2_OBJECT}" - COMMAND zig1 ${BUILD_ZIG2_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" - COMMENT STATUS "Building stage2 object ${ZIG2_OBJECT}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - ) - if (WIN32) - set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2.exe") - else() - set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2") - endif() -else() - add_custom_command( - OUTPUT "${ZIG2_OBJECT}" - COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG2_ARGS} - DEPENDS ${ZIG_STAGE2_SOURCES} - COMMENT STATUS "Building stage2 component ${ZIG2_OBJECT}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - ) -endif() +set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") +set(BUILD_COMPILER_RT_ARGS + "${CMAKE_SOURCE_DIR}/lib" + "${CMAKE_BINARY_DIR}/zig1-cache" + "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" + build-obj lib/compiler_rt.zig -ofmt=c + --name compiler_rt + -target x86_64-linux-musl # TODO: autodetect in zig1.c + --color on # TODO: autodetect in zig1.c + -OReleaseFast +) + +add_custom_command( + OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" + COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) -# cmake won't let us configure an executable without C sources. -add_executable(zig2 "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG2_OBJECT}") +add_executable(zig2 ${ZIG2_C_SOURCE}) set_target_properties(zig2 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} + COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS} + LINK_FLAGS ${ZIG2_LINK_FLAGS} ) -target_link_libraries(zig2 zigstage1) -if(MSVC) - target_link_libraries(zig2 ntdll.lib) -elseif(MINGW) - target_link_libraries(zig2 ntdll) -endif() -set(ZIG_BUILD_ARGS - --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" - "-Dconfig_h=${ZIG_CONFIG_H_OUT}" - "-Denable-llvm" - ${ZIG_RELEASE_ARG} - ${ZIG_STATIC_ARG} - ${ZIG_NO_LIB_ARG} - ${ZIG_SINGLE_THREADED_ARG} - "-Dtarget=${ZIG_TARGET_TRIPLE}" - "-Dcpu=${ZIG_TARGET_MCPU}" - "-Dversion-string=${RESOLVED_ZIG_VERSION}" -) -add_custom_target(stage3 ALL - COMMAND zig2 build compile ${ZIG_BUILD_ARGS} - DEPENDS zig2 - COMMENT STATUS "Building stage3" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" -) -install(CODE "set(ZIG_EXECUTABLE \"${ZIG_EXECUTABLE}\")") -install(CODE "set(ZIG_BUILD_ARGS \"${ZIG_BUILD_ARGS}\")") -install(CODE "set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")") -install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")") -install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/install.cmake") + + diff --git a/stage1/config.h.in b/stage1/config.h.in new file mode 100644 index 000000000000..2d4fff6df297 --- /dev/null +++ b/stage1/config.h.in @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_CONFIG_H +#define ZIG_CONFIG_H + +// Used by zig0.cpp +#define ZIG_VERSION_MAJOR @ZIG_VERSION_MAJOR@ +#define ZIG_VERSION_MINOR @ZIG_VERSION_MINOR@ +#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ +#define ZIG_VERSION_STRING "@ZIG_VERSION@" + +// Used by build.zig for communicating build information to self hosted build. +#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" +#define ZIG_LLVM_LINK_MODE "@LLVM_LINK_MODE@" +#define ZIG_CMAKE_PREFIX_PATH "@ZIG_CMAKE_PREFIX_PATH@" +#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@" +#define ZIG_LLD_INCLUDE_PATH "@LLD_INCLUDE_DIRS@" +#define ZIG_LLD_LIBRARIES "@LLD_LIBRARIES@" +#define ZIG_CLANG_LIBRARIES "@CLANG_LIBRARIES@" +#define ZIG_LLVM_INCLUDE_PATH "@LLVM_INCLUDE_DIRS@" +#define ZIG_LLVM_LIB_PATH "@LLVM_LIBDIRS@" +#define ZIG_LLVM_LIBRARIES "@LLVM_LIBRARIES@" +#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" + +#endif diff --git a/src/config.zig.in b/stage1/config.zig.in similarity index 72% rename from src/config.zig.in rename to stage1/config.zig.in index 2a0d45c010f8..48d1f75adbcb 100644 --- a/src/config.zig.in +++ b/stage1/config.zig.in @@ -1,13 +1,13 @@ -pub const have_llvm = true; +pub const have_llvm = false; pub const llvm_has_m68k = false; pub const llvm_has_csky = false; pub const llvm_has_arc = false; pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@"; pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable; -pub const enable_logging: bool = @ZIG_ENABLE_LOGGING_BOOL@; +pub const enable_logging: bool = false; pub const enable_link_snapshots: bool = false; pub const enable_tracy = false; pub const value_tracing = false; -pub const have_stage1 = true; +pub const have_stage1 = false; pub const skip_non_native = false; -pub const only_c = false; +pub const only_c = true; diff --git a/stage1/zig1.c b/stage1/zig1.c new file mode 100755 index 000000000000..1cdac5a52b93 --- /dev/null +++ b/stage1/zig1.c @@ -0,0 +1,4220 @@ +// TODO get rid of _GNU_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum wasi_errno_t { + WASI_ESUCCESS = 0, + WASI_E2BIG = 1, + WASI_EACCES = 2, + WASI_EADDRINUSE = 3, + WASI_EADDRNOTAVAIL = 4, + WASI_EAFNOSUPPORT = 5, + WASI_EAGAIN = 6, + WASI_EALREADY = 7, + WASI_EBADF = 8, + WASI_EBADMSG = 9, + WASI_EBUSY = 10, + WASI_ECANCELED = 11, + WASI_ECHILD = 12, + WASI_ECONNABORTED = 13, + WASI_ECONNREFUSED = 14, + WASI_ECONNRESET = 15, + WASI_EDEADLK = 16, + WASI_EDESTADDRREQ = 17, + WASI_EDOM = 18, + WASI_EDQUOT = 19, + WASI_EEXIST = 20, + WASI_EFAULT = 21, + WASI_EFBIG = 22, + WASI_EHOSTUNREACH = 23, + WASI_EIDRM = 24, + WASI_EILSEQ = 25, + WASI_EINPROGRESS = 26, + WASI_EINTR = 27, + WASI_EINVAL = 28, + WASI_EIO = 29, + WASI_EISCONN = 30, + WASI_EISDIR = 31, + WASI_ELOOP = 32, + WASI_EMFILE = 33, + WASI_EMLINK = 34, + WASI_EMSGSIZE = 35, + WASI_EMULTIHOP = 36, + WASI_ENAMETOOLONG = 37, + WASI_ENETDOWN = 38, + WASI_ENETRESET = 39, + WASI_ENETUNREACH = 40, + WASI_ENFILE = 41, + WASI_ENOBUFS = 42, + WASI_ENODEV = 43, + WASI_ENOENT = 44, + WASI_ENOEXEC = 45, + WASI_ENOLCK = 46, + WASI_ENOLINK = 47, + WASI_ENOMEM = 48, + WASI_ENOMSG = 49, + WASI_ENOPROTOOPT = 50, + WASI_ENOSPC = 51, + WASI_ENOSYS = 52, + WASI_ENOTCONN = 53, + WASI_ENOTDIR = 54, + WASI_ENOTEMPTY = 55, + WASI_ENOTRECOVERABLE = 56, + WASI_ENOTSOCK = 57, + WASI_EOPNOTSUPP = 58, + WASI_ENOTTY = 59, + WASI_ENXIO = 60, + WASI_EOVERFLOW = 61, + WASI_EOWNERDEAD = 62, + WASI_EPERM = 63, + WASI_EPIPE = 64, + WASI_EPROTO = 65, + WASI_EPROTONOSUPPORT = 66, + WASI_EPROTOTYPE = 67, + WASI_ERANGE = 68, + WASI_EROFS = 69, + WASI_ESPIPE = 70, + WASI_ESRCH = 71, + WASI_ESTALE = 72, + WASI_ETIMEDOUT = 73, + WASI_ETXTBSY = 74, + WASI_EXDEV = 75, + WASI_ENOTCAPABLE = 76, +}; + +static void panic(const char *msg) { + fprintf(stderr, "%s\n", msg); + abort(); +} + +static uint32_t min_u32(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +static uint32_t rotl32(uint32_t n, unsigned c) { + const unsigned mask = CHAR_BIT * sizeof(n) - 1; + c &= mask & 31; + return (n << c) | (n >> ((-c) & mask)); +} + +static uint32_t rotr32(uint32_t n, unsigned c) { + const unsigned mask = CHAR_BIT * sizeof(n) - 1; + c &= mask & 31; + return (n >> c) | (n << ((-c) & mask)); +} + +static uint64_t rotl64(uint64_t n, unsigned c) { + const unsigned mask = CHAR_BIT * sizeof(n) - 1; + c &= mask & 63; + return (n << c) | (n >> ((-c) & mask)); +} + +static uint64_t rotr64(uint64_t n, unsigned c) { + const unsigned mask = CHAR_BIT * sizeof(n) - 1; + c &= mask & 63; + return (n >> c) | (n << ((-c) & mask)); +} + +static void *arena_alloc(size_t n) { + void *ptr = malloc(n); + if (!ptr) panic("out of memory"); + return ptr; +} + +static void *arena_realloc(void *ptr, size_t new_n) { + void *new_ptr = realloc(ptr, new_n); + if (!new_ptr) panic("out of memory"); + return new_ptr; +} + +static int err_wrap(const char *prefix, int rc) { + if (rc == -1) { + perror(prefix); + abort(); + } + return rc; +} + +static bool bs_isSet(const uint32_t *bitset, uint32_t index) { + return (bitset[index >> 5] >> (index & 0x1f)) & 1; +} +static void bs_set(uint32_t *bitset, uint32_t index) { + bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f)); +} +static void bs_unset(uint32_t *bitset, uint32_t index) { + bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f)); +} +static void bs_setValue(uint32_t *bitset, uint32_t index, bool value) { + if (value) bs_set(bitset, index); else bs_unset(bitset, index); +} + +struct ByteSlice { + char *ptr; + size_t len; +}; + +static struct ByteSlice read_file_alloc(const char *file_path) { + FILE *f = fopen(file_path, "rb"); + if (!f) { + fprintf(stderr, "failed to read %s: ", file_path); + perror(""); + abort(); + } + if (fseek(f, 0L, SEEK_END) == -1) panic("failed to seek"); + struct ByteSlice res; + res.len = ftell(f); + res.ptr = malloc(res.len); + rewind(f); + size_t amt_read = fread(res.ptr, 1, res.len, f); + if (amt_read != res.len) panic("short read"); + fclose(f); + return res; +} + + +struct Preopen { + int wasi_fd; + int host_fd; + const char *name; + size_t name_len; +}; + +static struct Preopen preopens_buffer[10]; +static size_t preopens_len = 0; + +static void add_preopen(int wasi_fd, const char *name, int host_fd) { + preopens_buffer[preopens_len].wasi_fd = wasi_fd; + preopens_buffer[preopens_len].host_fd = host_fd; + preopens_buffer[preopens_len].name = name; + preopens_buffer[preopens_len].name_len = strlen(name); + preopens_len += 1; +} + +static const struct Preopen *find_preopen(int32_t wasi_fd) { + for (size_t i = 0; i < preopens_len; i += 1) { + const struct Preopen *preopen = &preopens_buffer[i]; + if (preopen->wasi_fd == wasi_fd) { + return preopen; + } + } + return NULL; +} + +static const size_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB + +static uint16_t read_u16_le(const char *ptr) { + const uint8_t *u8_ptr = (const uint8_t *)ptr; + return + (((uint64_t)u8_ptr[0]) << 0x00) | + (((uint64_t)u8_ptr[1]) << 0x08); +} + +static int16_t read_i16_le(const char *ptr) { + return read_u16_le(ptr); +} + +static uint32_t read_u32_le(const char *ptr) { + const uint8_t *u8_ptr = (const uint8_t *)ptr; + return + (((uint64_t)u8_ptr[0]) << 0x00) | + (((uint64_t)u8_ptr[1]) << 0x08) | + (((uint64_t)u8_ptr[2]) << 0x10) | + (((uint64_t)u8_ptr[3]) << 0x18); +} + +static uint32_t read_i32_le(const char *ptr) { + return read_u32_le(ptr); +} + +static uint64_t read_u64_le(const char *ptr) { + const uint8_t *u8_ptr = (const uint8_t *)ptr; + return + (((uint64_t)u8_ptr[0]) << 0x00) | + (((uint64_t)u8_ptr[1]) << 0x08) | + (((uint64_t)u8_ptr[2]) << 0x10) | + (((uint64_t)u8_ptr[3]) << 0x18) | + (((uint64_t)u8_ptr[4]) << 0x20) | + (((uint64_t)u8_ptr[5]) << 0x28) | + (((uint64_t)u8_ptr[6]) << 0x30) | + (((uint64_t)u8_ptr[7]) << 0x38); +} + +static void write_u16_le(char *ptr, uint16_t x) { + uint8_t *u8_ptr = (uint8_t*)ptr; + u8_ptr[0] = (x >> 0x00); + u8_ptr[1] = (x >> 0x08); +} + +static void write_u32_le(char *ptr, uint32_t x) { + uint8_t *u8_ptr = (uint8_t*)ptr; + u8_ptr[0] = (x >> 0x00); + u8_ptr[1] = (x >> 0x08); + u8_ptr[2] = (x >> 0x10); + u8_ptr[3] = (x >> 0x18); +} + +static void write_u64_le(char *ptr, uint64_t x) { + uint8_t *u8_ptr = (uint8_t*)ptr; + u8_ptr[0] = (x >> 0x00); + u8_ptr[1] = (x >> 0x08); + u8_ptr[2] = (x >> 0x10); + u8_ptr[3] = (x >> 0x18); + u8_ptr[4] = (x >> 0x20); + u8_ptr[5] = (x >> 0x28); + u8_ptr[6] = (x >> 0x30); + u8_ptr[7] = (x >> 0x38); +} + +static uint32_t read32_uleb128(const char *ptr, uint32_t *i) { + uint32_t result = 0; + uint32_t shift = 0; + + for (;;) { + uint32_t byte = ptr[*i]; + *i += 1; + result |= ((byte & 0x7f) << shift); + shift += 7; + if ((byte & 0x80) == 0) return result; + if (shift >= 32) panic("read32_uleb128 failed"); + } +} + +static int64_t read64_ileb128(const char *ptr, uint32_t *i) { + int64_t result = 0; + uint32_t shift = 0; + + for (;;) { + uint64_t byte = ptr[*i]; + *i += 1; + result |= ((byte & 0x7f) << shift); + shift += 7; + if ((byte & 0x80) == 0) { + if ((byte & 0x40) && (shift < 64)) { + uint64_t extend = 0; + result |= (~extend << shift); + } + return result; + } + if (shift >= 64) panic("read64_ileb128 failed"); + } +} + +static int32_t read32_ileb128(const char *ptr, uint32_t *i) { + return read64_ileb128(ptr, i); +} + +static struct ByteSlice read_name(char *ptr, uint32_t *i) { + uint32_t len = read32_uleb128(ptr, i); + struct ByteSlice res; + res.ptr = ptr + *i; + res.len = len; + *i += len; + return res; +} + +enum Section { + Section_custom, + Section_type, + Section_import, + Section_function, + Section_table, + Section_memory, + Section_global, + Section_export, + Section_start, + Section_element, + Section_code, + Section_data, + Section_data_count, +}; + +enum Op { + Op_unreachable, + Op_br_void, + Op_br_32, + Op_br_64, + Op_br_if_nez_void, + Op_br_if_nez_32, + Op_br_if_nez_64, + Op_br_if_eqz_void, + Op_br_if_eqz_32, + Op_br_if_eqz_64, + Op_br_table_void, + Op_br_table_32, + Op_br_table_64, + Op_return_void, + Op_return_32, + Op_return_64, + Op_call, + Op_drop_32, + Op_drop_64, + Op_select_32, + Op_select_64, + Op_local_get_32, + Op_local_get_64, + Op_local_set_32, + Op_local_set_64, + Op_local_tee_32, + Op_local_tee_64, + Op_global_get_0_32, + Op_global_get_32, + Op_global_set_0_32, + Op_global_set_32, + Op_const_32, + Op_const_64, + Op_add_32, + Op_and_32, + Op_wasm, + Op_wasm_prefixed, +}; + +enum WasmOp { + WasmOp_unreachable = 0x00, + WasmOp_nop = 0x01, + WasmOp_block = 0x02, + WasmOp_loop = 0x03, + WasmOp_if = 0x04, + WasmOp_else = 0x05, + WasmOp_end = 0x0B, + WasmOp_br = 0x0C, + WasmOp_br_if = 0x0D, + WasmOp_br_table = 0x0E, + WasmOp_return = 0x0F, + WasmOp_call = 0x10, + WasmOp_call_indirect = 0x11, + WasmOp_drop = 0x1A, + WasmOp_select = 0x1B, + WasmOp_local_get = 0x20, + WasmOp_local_set = 0x21, + WasmOp_local_tee = 0x22, + WasmOp_global_get = 0x23, + WasmOp_global_set = 0x24, + WasmOp_i32_load = 0x28, + WasmOp_i64_load = 0x29, + WasmOp_f32_load = 0x2A, + WasmOp_f64_load = 0x2B, + WasmOp_i32_load8_s = 0x2C, + WasmOp_i32_load8_u = 0x2D, + WasmOp_i32_load16_s = 0x2E, + WasmOp_i32_load16_u = 0x2F, + WasmOp_i64_load8_s = 0x30, + WasmOp_i64_load8_u = 0x31, + WasmOp_i64_load16_s = 0x32, + WasmOp_i64_load16_u = 0x33, + WasmOp_i64_load32_s = 0x34, + WasmOp_i64_load32_u = 0x35, + WasmOp_i32_store = 0x36, + WasmOp_i64_store = 0x37, + WasmOp_f32_store = 0x38, + WasmOp_f64_store = 0x39, + WasmOp_i32_store8 = 0x3A, + WasmOp_i32_store16 = 0x3B, + WasmOp_i64_store8 = 0x3C, + WasmOp_i64_store16 = 0x3D, + WasmOp_i64_store32 = 0x3E, + WasmOp_memory_size = 0x3F, + WasmOp_memory_grow = 0x40, + WasmOp_i32_const = 0x41, + WasmOp_i64_const = 0x42, + WasmOp_f32_const = 0x43, + WasmOp_f64_const = 0x44, + WasmOp_i32_eqz = 0x45, + WasmOp_i32_eq = 0x46, + WasmOp_i32_ne = 0x47, + WasmOp_i32_lt_s = 0x48, + WasmOp_i32_lt_u = 0x49, + WasmOp_i32_gt_s = 0x4A, + WasmOp_i32_gt_u = 0x4B, + WasmOp_i32_le_s = 0x4C, + WasmOp_i32_le_u = 0x4D, + WasmOp_i32_ge_s = 0x4E, + WasmOp_i32_ge_u = 0x4F, + WasmOp_i64_eqz = 0x50, + WasmOp_i64_eq = 0x51, + WasmOp_i64_ne = 0x52, + WasmOp_i64_lt_s = 0x53, + WasmOp_i64_lt_u = 0x54, + WasmOp_i64_gt_s = 0x55, + WasmOp_i64_gt_u = 0x56, + WasmOp_i64_le_s = 0x57, + WasmOp_i64_le_u = 0x58, + WasmOp_i64_ge_s = 0x59, + WasmOp_i64_ge_u = 0x5A, + WasmOp_f32_eq = 0x5B, + WasmOp_f32_ne = 0x5C, + WasmOp_f32_lt = 0x5D, + WasmOp_f32_gt = 0x5E, + WasmOp_f32_le = 0x5F, + WasmOp_f32_ge = 0x60, + WasmOp_f64_eq = 0x61, + WasmOp_f64_ne = 0x62, + WasmOp_f64_lt = 0x63, + WasmOp_f64_gt = 0x64, + WasmOp_f64_le = 0x65, + WasmOp_f64_ge = 0x66, + WasmOp_i32_clz = 0x67, + WasmOp_i32_ctz = 0x68, + WasmOp_i32_popcnt = 0x69, + WasmOp_i32_add = 0x6A, + WasmOp_i32_sub = 0x6B, + WasmOp_i32_mul = 0x6C, + WasmOp_i32_div_s = 0x6D, + WasmOp_i32_div_u = 0x6E, + WasmOp_i32_rem_s = 0x6F, + WasmOp_i32_rem_u = 0x70, + WasmOp_i32_and = 0x71, + WasmOp_i32_or = 0x72, + WasmOp_i32_xor = 0x73, + WasmOp_i32_shl = 0x74, + WasmOp_i32_shr_s = 0x75, + WasmOp_i32_shr_u = 0x76, + WasmOp_i32_rotl = 0x77, + WasmOp_i32_rotr = 0x78, + WasmOp_i64_clz = 0x79, + WasmOp_i64_ctz = 0x7A, + WasmOp_i64_popcnt = 0x7B, + WasmOp_i64_add = 0x7C, + WasmOp_i64_sub = 0x7D, + WasmOp_i64_mul = 0x7E, + WasmOp_i64_div_s = 0x7F, + WasmOp_i64_div_u = 0x80, + WasmOp_i64_rem_s = 0x81, + WasmOp_i64_rem_u = 0x82, + WasmOp_i64_and = 0x83, + WasmOp_i64_or = 0x84, + WasmOp_i64_xor = 0x85, + WasmOp_i64_shl = 0x86, + WasmOp_i64_shr_s = 0x87, + WasmOp_i64_shr_u = 0x88, + WasmOp_i64_rotl = 0x89, + WasmOp_i64_rotr = 0x8A, + WasmOp_f32_abs = 0x8B, + WasmOp_f32_neg = 0x8C, + WasmOp_f32_ceil = 0x8D, + WasmOp_f32_floor = 0x8E, + WasmOp_f32_trunc = 0x8F, + WasmOp_f32_nearest = 0x90, + WasmOp_f32_sqrt = 0x91, + WasmOp_f32_add = 0x92, + WasmOp_f32_sub = 0x93, + WasmOp_f32_mul = 0x94, + WasmOp_f32_div = 0x95, + WasmOp_f32_min = 0x96, + WasmOp_f32_max = 0x97, + WasmOp_f32_copysign = 0x98, + WasmOp_f64_abs = 0x99, + WasmOp_f64_neg = 0x9A, + WasmOp_f64_ceil = 0x9B, + WasmOp_f64_floor = 0x9C, + WasmOp_f64_trunc = 0x9D, + WasmOp_f64_nearest = 0x9E, + WasmOp_f64_sqrt = 0x9F, + WasmOp_f64_add = 0xA0, + WasmOp_f64_sub = 0xA1, + WasmOp_f64_mul = 0xA2, + WasmOp_f64_div = 0xA3, + WasmOp_f64_min = 0xA4, + WasmOp_f64_max = 0xA5, + WasmOp_f64_copysign = 0xA6, + WasmOp_i32_wrap_i64 = 0xA7, + WasmOp_i32_trunc_f32_s = 0xA8, + WasmOp_i32_trunc_f32_u = 0xA9, + WasmOp_i32_trunc_f64_s = 0xAA, + WasmOp_i32_trunc_f64_u = 0xAB, + WasmOp_i64_extend_i32_s = 0xAC, + WasmOp_i64_extend_i32_u = 0xAD, + WasmOp_i64_trunc_f32_s = 0xAE, + WasmOp_i64_trunc_f32_u = 0xAF, + WasmOp_i64_trunc_f64_s = 0xB0, + WasmOp_i64_trunc_f64_u = 0xB1, + WasmOp_f32_convert_i32_s = 0xB2, + WasmOp_f32_convert_i32_u = 0xB3, + WasmOp_f32_convert_i64_s = 0xB4, + WasmOp_f32_convert_i64_u = 0xB5, + WasmOp_f32_demote_f64 = 0xB6, + WasmOp_f64_convert_i32_s = 0xB7, + WasmOp_f64_convert_i32_u = 0xB8, + WasmOp_f64_convert_i64_s = 0xB9, + WasmOp_f64_convert_i64_u = 0xBA, + WasmOp_f64_promote_f32 = 0xBB, + WasmOp_i32_reinterpret_f32 = 0xBC, + WasmOp_i64_reinterpret_f64 = 0xBD, + WasmOp_f32_reinterpret_i32 = 0xBE, + WasmOp_f64_reinterpret_i64 = 0xBF, + WasmOp_i32_extend8_s = 0xC0, + WasmOp_i32_extend16_s = 0xC1, + WasmOp_i64_extend8_s = 0xC2, + WasmOp_i64_extend16_s = 0xC3, + WasmOp_i64_extend32_s = 0xC4, + + WasmOp_prefixed = 0xFC, +}; + +enum WasmPrefixedOp { + WasmPrefixedOp_i32_trunc_sat_f32_s = 0x00, + WasmPrefixedOp_i32_trunc_sat_f32_u = 0x01, + WasmPrefixedOp_i32_trunc_sat_f64_s = 0x02, + WasmPrefixedOp_i32_trunc_sat_f64_u = 0x03, + WasmPrefixedOp_i64_trunc_sat_f32_s = 0x04, + WasmPrefixedOp_i64_trunc_sat_f32_u = 0x05, + WasmPrefixedOp_i64_trunc_sat_f64_s = 0x06, + WasmPrefixedOp_i64_trunc_sat_f64_u = 0x07, + WasmPrefixedOp_memory_init = 0x08, + WasmPrefixedOp_data_drop = 0x09, + WasmPrefixedOp_memory_copy = 0x0A, + WasmPrefixedOp_memory_fill = 0x0B, + WasmPrefixedOp_table_init = 0x0C, + WasmPrefixedOp_elem_drop = 0x0D, + WasmPrefixedOp_table_copy = 0x0E, + WasmPrefixedOp_table_grow = 0x0F, + WasmPrefixedOp_table_size = 0x10, + WasmPrefixedOp_table_fill = 0x11, +}; + +static const uint32_t wasm_page_size = 64 * 1024; + +struct ProgramCounter { + uint32_t opcode; + uint32_t operand; +}; + +struct TypeInfo { + uint32_t param_count; + // bitset with param_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit + uint32_t param_types; + uint32_t result_count; + // bitset with result_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit + uint32_t result_types; +}; + +struct Function { + // Index to start of code in opcodes/operands. + struct ProgramCounter entry_pc; + uint32_t type_idx; + uint32_t locals_count; + // multi-word bitset with vm->types[type_idx].param_count + locals_count bits + // indexed from lsb of the first element, 0 -> 32-bit, 1 -> 64-bit + uint32_t *local_types; +}; + +enum ImpMod { + ImpMod_wasi_snapshot_preview1, +}; + +enum ImpName { + ImpName_args_get, + ImpName_args_sizes_get, + ImpName_clock_time_get, + ImpName_debug, + ImpName_debug_slice, + ImpName_environ_get, + ImpName_environ_sizes_get, + ImpName_fd_close, + ImpName_fd_fdstat_get, + ImpName_fd_filestat_get, + ImpName_fd_filestat_set_size, + ImpName_fd_filestat_set_times, + ImpName_fd_pread, + ImpName_fd_prestat_dir_name, + ImpName_fd_prestat_get, + ImpName_fd_pwrite, + ImpName_fd_read, + ImpName_fd_readdir, + ImpName_fd_write, + ImpName_path_create_directory, + ImpName_path_filestat_get, + ImpName_path_open, + ImpName_path_remove_directory, + ImpName_path_rename, + ImpName_path_unlink_file, + ImpName_proc_exit, + ImpName_random_get, +}; + +struct Import { + enum ImpMod mod; + enum ImpName name; + uint32_t type_idx; +}; + +struct VirtualMachine { + uint64_t *stack; + /// Points to one after the last stack item. + uint32_t stack_top; + struct ProgramCounter pc; + uint32_t memory_len; + const char *mod_ptr; + uint8_t *opcodes; + uint32_t *operands; + struct Function *functions; + /// Type index to start of type in module_bytes. + struct TypeInfo *types; + uint64_t *globals; + char *memory; + struct Import *imports; + uint32_t imports_len; + char **args; + uint32_t *table; +}; + +static int to_host_fd(int32_t wasi_fd) { + const struct Preopen *preopen = find_preopen(wasi_fd); + if (!preopen) return wasi_fd; + return preopen->host_fd; +} + +static enum wasi_errno_t to_wasi_err(int err) { + switch (err) { + case EACCES: return WASI_EACCES; + case EDQUOT: return WASI_EDQUOT; + case EIO: return WASI_EIO; + case EFBIG: return WASI_EFBIG; + case ENOSPC: return WASI_ENOSPC; + case EPIPE: return WASI_EPIPE; + case EBADF: return WASI_EBADF; + case ENOMEM: return WASI_ENOMEM; + case ENOENT: return WASI_ENOENT; + case EEXIST: return WASI_EEXIST; + default: + fprintf(stderr, "unexpected errno: %s\n", strerror(err)); + abort(); + }; +} + +/// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; +static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, + uint32_t argc, uint32_t argv_buf_size) +{ + uint32_t args_len = 0; + size_t buf_size = 0; + while (vm->args[args_len]) { + buf_size += strlen(vm->args[args_len]) + 1; + args_len += 1; + } + write_u32_le(vm->memory + argc, args_len); + write_u32_le(vm->memory + argv_buf_size, buf_size); + return WASI_ESUCCESS; +} + +/// extern fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; +static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, + uint32_t argv, uint32_t argv_buf) +{ + panic("TODO implement wasi_args_get"); + //var argv_buf_i: usize = 0; + //for (vm->args) |arg, arg_i| { + // // Write the arg to the buffer. + // const argv_ptr = argv_buf + argv_buf_i; + // const arg_len = mem.span(arg).len + 1; + // mem.copy(u8, vm->memory[argv_buf + argv_buf_i ..], arg[0..arg_len]); + // argv_buf_i += arg_len; + + // write_u32_le(vm->memory[argv + 4 * arg_i ..][0..4], @intCast(u32, argv_ptr)); + //} + return WASI_ESUCCESS; +} + +/// extern fn random_get(buf: [*]u8, buf_len: usize) errno_t; +static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, + uint32_t buf, uint32_t buf_len) +{ + panic("TODO implement wasi_random_get"); + //const host_buf = vm->memory[buf..][0..buf_len]; + //std.crypto.random.bytes(host_buf); + return WASI_ESUCCESS; +} + +/// fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t; +/// const prestat_t = extern struct { +/// pr_type: u8, +/// u: usize, +/// }; +static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, + int32_t fd, uint32_t buf) +{ + panic("TODO implement wasi_fd_prestat_get"); + //const preopen = findPreopen(fd) orelse return .BADF; + //write_u32_le(vm->memory[buf + 0 ..][0..4], 0); + //write_u32_le(vm->memory[buf + 4 ..][0..4], @intCast(u32, preopen.name.len)); + return WASI_ESUCCESS; +} + +/// fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t; +static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm, + int32_t fd, uint32_t path, uint32_t path_len) +{ + panic("TODO implement wasi_fd_prestat_dir_name"); + //const preopen = findPreopen(fd) orelse return .BADF; + //assert(path_len == preopen.name.len); + //mem.copy(u8, vm->memory[path..], preopen.name); + return WASI_ESUCCESS; +} + +/// extern fn fd_close(fd: fd_t) errno_t; +static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) { + panic("TODO implement wasi_fd_close"); + //_ = vm; + //const host_fd = toHostFd(fd); + //os.close(host_fd); + return WASI_ESUCCESS; +} + +static enum wasi_errno_t wasi_fd_read( + struct VirtualMachine *vm, + int32_t fd, + uint32_t iovs, // [*]const iovec_t + uint32_t iovs_len, // usize + uint32_t nread // *usize +) { + panic("TODO implement wasi_fd_read"); + //const host_fd = toHostFd(fd); + //var i: u32 = 0; + //var total_read: usize = 0; + //while (i < iovs_len) : (i += 1) { + // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); + // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); + // const buf = vm->memory[ptr..][0..len]; + // const read = os.read(host_fd, buf) catch |err| return toWasiError(err); + // trace_log.debug("read {d} bytes out of {d}", .{ read, buf.len }); + // total_read += read; + // if (read != buf.len) break; + //} + //write_u32_le(vm->memory[nread..][0..4], @intCast(u32, total_read)); + return WASI_ESUCCESS; +} + +/// extern fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t; +/// const ciovec_t = extern struct { +/// base: [*]const u8, +/// len: usize, +/// }; +static enum wasi_errno_t wasi_fd_write(struct VirtualMachine *vm, + int32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t nwritten) +{ + int host_fd = to_host_fd(fd); + size_t total_written = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); + uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); + ssize_t written = write(host_fd, vm->memory + ptr, len); + if (written < 0) return to_wasi_err(errno); + total_written += written; + if (written != len) break; + } + write_u32_le(vm->memory + nwritten, total_written); + return WASI_ESUCCESS; +} + +static enum wasi_errno_t wasi_fd_pwrite( + struct VirtualMachine *vm, + int32_t fd, + uint32_t iovs, // [*]const ciovec_t + uint32_t iovs_len, // usize + uint64_t offset, // wasi.filesize_t, + uint32_t written_ptr // *usize +) { + panic("TODO implement wasi_fd_pwrite"); + //const host_fd = toHostFd(fd); + //var i: u32 = 0; + //var written: usize = 0; + //while (i < iovs_len) : (i += 1) { + // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); + // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); + // const buf = vm->memory[ptr..][0..len]; + // const w = os.pwrite(host_fd, buf, offset + written) catch |err| return toWasiError(err); + // written += w; + // if (w != buf.len) break; + //} + //write_u32_le(vm->memory[written_ptr..][0..4], @intCast(u32, written)); + return WASI_ESUCCESS; +} + +///extern fn path_open( +/// dirfd: fd_t, +/// dirflags: lookupflags_t, +/// path: [*]const u8, +/// path_len: usize, +/// oflags: oflags_t, +/// fs_rights_base: rights_t, +/// fs_rights_inheriting: rights_t, +/// fs_flags: fdflags_t, +/// fd: *fd_t, +///) errno_t; +static enum wasi_errno_t wasi_path_open( + struct VirtualMachine *vm, + int32_t dirfd, + uint32_t dirflags, // wasi.lookupflags_t, + uint32_t path, + uint32_t path_len, + uint16_t oflags, // wasi.oflags_t, + uint64_t fs_rights_base, // wasi.rights_t, + uint64_t fs_rights_inheriting, // wasi.rights_t, + uint16_t fs_flags, // wasi.fdflags_t, + uint32_t fd +) { + panic("TODO implement wasi_path_open"); + //const sub_path = vm->memory[path..][0..path_len]; + //const host_fd = toHostFd(dirfd); + //var flags: u32 = @as(u32, if (oflags & wasi.O.CREAT != 0) os.O.CREAT else 0) | + // @as(u32, if (oflags & wasi.O.DIRECTORY != 0) os.O.DIRECTORY else 0) | + // @as(u32, if (oflags & wasi.O.EXCL != 0) os.O.EXCL else 0) | + // @as(u32, if (oflags & wasi.O.TRUNC != 0) os.O.TRUNC else 0) | + // @as(u32, if (fs_flags & wasi.FDFLAG.APPEND != 0) os.O.APPEND else 0) | + // @as(u32, if (fs_flags & wasi.FDFLAG.DSYNC != 0) os.O.DSYNC else 0) | + // @as(u32, if (fs_flags & wasi.FDFLAG.NONBLOCK != 0) os.O.NONBLOCK else 0) | + // @as(u32, if (fs_flags & wasi.FDFLAG.SYNC != 0) os.O.SYNC else 0); + //if ((fs_rights_base & wasi.RIGHT.FD_READ != 0) and + // (fs_rights_base & wasi.RIGHT.FD_WRITE != 0)) + //{ + // flags |= os.O.RDWR; + //} else if (fs_rights_base & wasi.RIGHT.FD_WRITE != 0) { + // flags |= os.O.WRONLY; + //} else if (fs_rights_base & wasi.RIGHT.FD_READ != 0) { + // flags |= os.O.RDONLY; // no-op because O_RDONLY is 0 + //} + //const mode = 0o644; + //const res_fd = os.openat(host_fd, sub_path, flags, mode) catch |err| return toWasiError(err); + //mem.writeIntLittle(i32, vm->memory[fd..][0..4], res_fd); + return WASI_ESUCCESS; +} + +static enum wasi_errno_t wasi_path_filestat_get( + struct VirtualMachine *vm, + int32_t fd, + uint32_t flags, // wasi.lookupflags_t, + uint32_t path, // [*]const u8 + uint32_t path_len, // usize + uint32_t buf // *filestat_t +) { + panic("TODO implement wasi_path_filestat_get"); + //const sub_path = vm->memory[path..][0..path_len]; + //const host_fd = toHostFd(fd); + //const dir: fs.Dir = .{ .fd = host_fd }; + //const stat = dir.statFile(sub_path) catch |err| return toWasiError(err); + //return finishWasiStat(vm, buf, stat); + return WASI_ESUCCESS; +} + +/// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; +static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, int32_t fd, uint32_t path, uint32_t path_len) { + panic("TODO implement wasi_path_create_directory"); + //const sub_path = vm->memory[path..][0..path_len]; + //trace_log.debug("wasi_path_create_directory fd={d} path={s}", .{ fd, sub_path }); + //const host_fd = toHostFd(fd); + //const dir: fs.Dir = .{ .fd = host_fd }; + //dir.makeDir(sub_path) catch |err| return toWasiError(err); + return WASI_ESUCCESS; +} + +static enum wasi_errno_t wasi_path_rename( + struct VirtualMachine *vm, + int32_t old_fd, + uint32_t old_path_ptr, // [*]const u8 + uint32_t old_path_len, // usize + int32_t new_fd, + uint32_t new_path_ptr, // [*]const u8 + uint32_t new_path_len // usize +) { + panic("TODO implement wasi_path_rename"); + //const old_path = vm->memory[old_path_ptr..][0..old_path_len]; + //const new_path = vm->memory[new_path_ptr..][0..new_path_len]; + //trace_log.debug("wasi_path_rename old_fd={d} old_path={s} new_fd={d} new_path={s}", .{ + // old_fd, old_path, new_fd, new_path, + //}); + //const old_host_fd = toHostFd(old_fd); + //const new_host_fd = toHostFd(new_fd); + //os.renameat(old_host_fd, old_path, new_host_fd, new_path) catch |err| return toWasiError(err); + return WASI_ESUCCESS; +} + +/// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; +static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { + panic("TODO implement wasi_fd_filestat_get"); + //const host_fd = toHostFd(fd); + //const file = fs.File{ .handle = host_fd }; + //const stat = file.stat() catch |err| return toWasiError(err); + //return finishWasiStat(vm, buf, stat); + return WASI_ESUCCESS; +} + +static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, + int32_t fd, uint64_t size) +{ + panic("TODO implement wasi_fd_filestat_set_size"); + //_ = vm; + //const host_fd = toHostFd(fd); + //os.ftruncate(host_fd, size) catch |err| return toWasiError(err); + return WASI_ESUCCESS; +} + +/// pub extern "wasi_snapshot_preview1" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t; +/// pub const fdstat_t = extern struct { +/// fs_filetype: filetype_t, u8 +/// fs_flags: fdflags_t, u16 +/// fs_rights_base: rights_t, u64 +/// fs_rights_inheriting: rights_t, u64 +/// }; +static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { + panic("TODO implement wasi_fd_fdstat_get"); + //const host_fd = toHostFd(fd); + //const file = fs.File{ .handle = host_fd }; + //const stat = file.stat() catch |err| return toWasiError(err); + //mem.writeIntLittle(u16, vm->memory[buf + 0x00 ..][0..2], @enumToInt(toWasiFileType(stat.kind))); + //mem.writeIntLittle(u16, vm->memory[buf + 0x02 ..][0..2], 0); // flags + //mem.writeIntLittle(u64, vm->memory[buf + 0x08 ..][0..8], math.maxInt(u64)); // rights_base + //mem.writeIntLittle(u64, vm->memory[buf + 0x10 ..][0..8], math.maxInt(u64)); // rights_inheriting + return WASI_ESUCCESS; +} + +/// extern fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; +static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, + uint32_t clock_id, uint64_t precision, uint32_t timestamp) +{ + panic("TODO implement wasi_clock_time_get"); + ////const host_clock_id = toHostClockId(clock_id); + //_ = precision; + //_ = clock_id; + //const wasi_ts = toWasiTimestamp(std.time.nanoTimestamp()); + //mem.writeIntLittle(u64, vm->memory[timestamp..][0..8], wasi_ts); + return WASI_ESUCCESS; +} + +///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; +void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { + panic("TODO implement wasi_debug"); + //const s = mem.sliceTo(vm->memory[text..], 0); + //trace_log.debug("wasi_debug: '{s}' number={d} {x}", .{ s, n, n }); +} + +/// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; +void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { + panic("TODO implement wasi_debug_slice"); + //const s = vm->memory[ptr..][0..len]; + //trace_log.debug("wasi_debug_slice: '{s}'", .{s}); +} + + + +struct Label { + enum WasmOp opcode; + uint32_t stack_depth; + struct TypeInfo type_info; + // this is a UINT32_MAX terminated linked list that is stored in the operands array + uint32_t ref_list; + union { + struct ProgramCounter loop_pc; + uint32_t else_ref; + } extra; +}; + +static uint32_t Label_operandCount(const struct Label *label) { + if (label->opcode == WasmOp_loop) { + return label->type_info.param_count; + } else { + return label->type_info.result_count; + } +} + +static bool Label_operandType(const struct Label *label, uint32_t index) { + if (label->opcode == WasmOp_loop) { + return bs_isSet(&label->type_info.param_types, index); + } else { + return bs_isSet(&label->type_info.result_types, index); + } +} + +static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint32_t *code_i, + struct ProgramCounter *pc) +{ + const char *mod_ptr = vm->mod_ptr; + uint8_t *opcodes = vm->opcodes; + uint32_t *operands = vm->operands; + struct TypeInfo *func_type_info = &vm->types[func->type_idx]; + + uint32_t unreachable_depth = 0; + uint32_t stack_depth = func_type_info->param_count + func->locals_count + 2; + static uint32_t stack_types[1 << (12 - 3)]; + + static struct Label labels[1 << 9]; + uint32_t label_i = 0; + labels[label_i].opcode = WasmOp_block; + labels[label_i].stack_depth = stack_depth; + labels[label_i].type_info = vm->types[func->type_idx]; + labels[label_i].ref_list = UINT32_MAX; + + for (;;) { + enum WasmOp opcode = (uint8_t)mod_ptr[*code_i]; + *code_i += 1; + enum WasmPrefixedOp prefixed_opcode; + if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i); + + uint32_t initial_stack_depth = stack_depth; + if (unreachable_depth == 0) { + switch (opcode) { + case WasmOp_unreachable: + case WasmOp_nop: + case WasmOp_block: + case WasmOp_loop: + case WasmOp_else: + case WasmOp_end: + case WasmOp_br: + case WasmOp_call: + case WasmOp_return: + break; + + case WasmOp_if: + case WasmOp_br_if: + case WasmOp_br_table: + case WasmOp_call_indirect: + case WasmOp_drop: + case WasmOp_local_set: + case WasmOp_global_set: + stack_depth -= 1; + break; + + case WasmOp_select: + stack_depth -= 2; + break; + + case WasmOp_local_get: + case WasmOp_global_get: + case WasmOp_memory_size: + case WasmOp_i32_const: + case WasmOp_i64_const: + case WasmOp_f32_const: + case WasmOp_f64_const: + stack_depth += 1; + break; + + case WasmOp_local_tee: + case WasmOp_i32_load: + case WasmOp_i64_load: + case WasmOp_f32_load: + case WasmOp_f64_load: + case WasmOp_i32_load8_s: + case WasmOp_i32_load8_u: + case WasmOp_i32_load16_s: + case WasmOp_i32_load16_u: + case WasmOp_i64_load8_s: + case WasmOp_i64_load8_u: + case WasmOp_i64_load16_s: + case WasmOp_i64_load16_u: + case WasmOp_i64_load32_s: + case WasmOp_i64_load32_u: + case WasmOp_memory_grow: + case WasmOp_i32_eqz: + case WasmOp_i32_clz: + case WasmOp_i32_ctz: + case WasmOp_i32_popcnt: + case WasmOp_i64_eqz: + case WasmOp_i64_clz: + case WasmOp_i64_ctz: + case WasmOp_i64_popcnt: + case WasmOp_f32_abs: + case WasmOp_f32_neg: + case WasmOp_f32_ceil: + case WasmOp_f32_floor: + case WasmOp_f32_trunc: + case WasmOp_f32_nearest: + case WasmOp_f32_sqrt: + case WasmOp_f64_abs: + case WasmOp_f64_neg: + case WasmOp_f64_ceil: + case WasmOp_f64_floor: + case WasmOp_f64_trunc: + case WasmOp_f64_nearest: + case WasmOp_f64_sqrt: + case WasmOp_i32_wrap_i64: + case WasmOp_i32_trunc_f32_s: + case WasmOp_i32_trunc_f32_u: + case WasmOp_i32_trunc_f64_s: + case WasmOp_i32_trunc_f64_u: + case WasmOp_i64_extend_i32_s: + case WasmOp_i64_extend_i32_u: + case WasmOp_i64_trunc_f32_s: + case WasmOp_i64_trunc_f32_u: + case WasmOp_i64_trunc_f64_s: + case WasmOp_i64_trunc_f64_u: + case WasmOp_f32_convert_i32_s: + case WasmOp_f32_convert_i32_u: + case WasmOp_f32_convert_i64_s: + case WasmOp_f32_convert_i64_u: + case WasmOp_f32_demote_f64: + case WasmOp_f64_convert_i32_s: + case WasmOp_f64_convert_i32_u: + case WasmOp_f64_convert_i64_s: + case WasmOp_f64_convert_i64_u: + case WasmOp_f64_promote_f32: + case WasmOp_i32_reinterpret_f32: + case WasmOp_i64_reinterpret_f64: + case WasmOp_f32_reinterpret_i32: + case WasmOp_f64_reinterpret_i64: + case WasmOp_i32_extend8_s: + case WasmOp_i32_extend16_s: + case WasmOp_i64_extend8_s: + case WasmOp_i64_extend16_s: + case WasmOp_i64_extend32_s: + break; + + case WasmOp_i32_store: + case WasmOp_i64_store: + case WasmOp_f32_store: + case WasmOp_f64_store: + case WasmOp_i32_store8: + case WasmOp_i32_store16: + case WasmOp_i64_store8: + case WasmOp_i64_store16: + case WasmOp_i64_store32: + stack_depth -= 2; + break; + + case WasmOp_i32_eq: + case WasmOp_i32_ne: + case WasmOp_i32_lt_s: + case WasmOp_i32_lt_u: + case WasmOp_i32_gt_s: + case WasmOp_i32_gt_u: + case WasmOp_i32_le_s: + case WasmOp_i32_le_u: + case WasmOp_i32_ge_s: + case WasmOp_i32_ge_u: + case WasmOp_i64_eq: + case WasmOp_i64_ne: + case WasmOp_i64_lt_s: + case WasmOp_i64_lt_u: + case WasmOp_i64_gt_s: + case WasmOp_i64_gt_u: + case WasmOp_i64_le_s: + case WasmOp_i64_le_u: + case WasmOp_i64_ge_s: + case WasmOp_i64_ge_u: + case WasmOp_f32_eq: + case WasmOp_f32_ne: + case WasmOp_f32_lt: + case WasmOp_f32_gt: + case WasmOp_f32_le: + case WasmOp_f32_ge: + case WasmOp_f64_eq: + case WasmOp_f64_ne: + case WasmOp_f64_lt: + case WasmOp_f64_gt: + case WasmOp_f64_le: + case WasmOp_f64_ge: + case WasmOp_i32_add: + case WasmOp_i32_sub: + case WasmOp_i32_mul: + case WasmOp_i32_div_s: + case WasmOp_i32_div_u: + case WasmOp_i32_rem_s: + case WasmOp_i32_rem_u: + case WasmOp_i32_and: + case WasmOp_i32_or: + case WasmOp_i32_xor: + case WasmOp_i32_shl: + case WasmOp_i32_shr_s: + case WasmOp_i32_shr_u: + case WasmOp_i32_rotl: + case WasmOp_i32_rotr: + case WasmOp_i64_add: + case WasmOp_i64_sub: + case WasmOp_i64_mul: + case WasmOp_i64_div_s: + case WasmOp_i64_div_u: + case WasmOp_i64_rem_s: + case WasmOp_i64_rem_u: + case WasmOp_i64_and: + case WasmOp_i64_or: + case WasmOp_i64_xor: + case WasmOp_i64_shl: + case WasmOp_i64_shr_s: + case WasmOp_i64_shr_u: + case WasmOp_i64_rotl: + case WasmOp_i64_rotr: + case WasmOp_f32_add: + case WasmOp_f32_sub: + case WasmOp_f32_mul: + case WasmOp_f32_div: + case WasmOp_f32_min: + case WasmOp_f32_max: + case WasmOp_f32_copysign: + case WasmOp_f64_add: + case WasmOp_f64_sub: + case WasmOp_f64_mul: + case WasmOp_f64_div: + case WasmOp_f64_min: + case WasmOp_f64_max: + case WasmOp_f64_copysign: + stack_depth -= 1; + break; + + case WasmOp_prefixed: + switch (prefixed_opcode) { + case WasmPrefixedOp_i32_trunc_sat_f32_s: + case WasmPrefixedOp_i32_trunc_sat_f32_u: + case WasmPrefixedOp_i32_trunc_sat_f64_s: + case WasmPrefixedOp_i32_trunc_sat_f64_u: + case WasmPrefixedOp_i64_trunc_sat_f32_s: + case WasmPrefixedOp_i64_trunc_sat_f32_u: + case WasmPrefixedOp_i64_trunc_sat_f64_s: + case WasmPrefixedOp_i64_trunc_sat_f64_u: + break; + + case WasmPrefixedOp_memory_init: + case WasmPrefixedOp_memory_copy: + case WasmPrefixedOp_memory_fill: + case WasmPrefixedOp_table_init: + case WasmPrefixedOp_table_copy: + case WasmPrefixedOp_table_fill: + stack_depth -= 3; + break; + + case WasmPrefixedOp_data_drop: + case WasmPrefixedOp_elem_drop: + break; + + case WasmPrefixedOp_table_grow: + stack_depth -= 1; + break; + + case WasmPrefixedOp_table_size: + stack_depth += 1; + break; + + default: panic("unexpected prefixed opcode"); + } + break; + + default: panic("unexpected opcode"); + } + switch (opcode) { + case WasmOp_unreachable: + case WasmOp_nop: + case WasmOp_block: + case WasmOp_loop: + case WasmOp_else: + case WasmOp_end: + case WasmOp_br: + case WasmOp_call: + case WasmOp_return: + case WasmOp_if: + case WasmOp_br_if: + case WasmOp_br_table: + case WasmOp_call_indirect: + case WasmOp_drop: + case WasmOp_select: + case WasmOp_local_set: + case WasmOp_local_get: + case WasmOp_local_tee: + case WasmOp_global_set: + case WasmOp_global_get: + case WasmOp_i32_store: + case WasmOp_i64_store: + case WasmOp_f32_store: + case WasmOp_f64_store: + case WasmOp_i32_store8: + case WasmOp_i32_store16: + case WasmOp_i64_store8: + case WasmOp_i64_store16: + case WasmOp_i64_store32: + break; + + case WasmOp_i32_const: + case WasmOp_f32_const: + case WasmOp_memory_size: + case WasmOp_i32_load: + case WasmOp_f32_load: + case WasmOp_i32_load8_s: + case WasmOp_i32_load8_u: + case WasmOp_i32_load16_s: + case WasmOp_i32_load16_u: + case WasmOp_memory_grow: + case WasmOp_i32_eqz: + case WasmOp_i32_clz: + case WasmOp_i32_ctz: + case WasmOp_i32_popcnt: + case WasmOp_i64_eqz: + case WasmOp_f32_abs: + case WasmOp_f32_neg: + case WasmOp_f32_ceil: + case WasmOp_f32_floor: + case WasmOp_f32_trunc: + case WasmOp_f32_nearest: + case WasmOp_f32_sqrt: + case WasmOp_i32_wrap_i64: + case WasmOp_i32_trunc_f32_s: + case WasmOp_i32_trunc_f32_u: + case WasmOp_i32_trunc_f64_s: + case WasmOp_i32_trunc_f64_u: + case WasmOp_f32_convert_i32_s: + case WasmOp_f32_convert_i32_u: + case WasmOp_f32_convert_i64_s: + case WasmOp_f32_convert_i64_u: + case WasmOp_f32_demote_f64: + case WasmOp_i32_reinterpret_f32: + case WasmOp_f32_reinterpret_i32: + case WasmOp_i32_extend8_s: + case WasmOp_i32_extend16_s: + case WasmOp_i32_eq: + case WasmOp_i32_ne: + case WasmOp_i32_lt_s: + case WasmOp_i32_lt_u: + case WasmOp_i32_gt_s: + case WasmOp_i32_gt_u: + case WasmOp_i32_le_s: + case WasmOp_i32_le_u: + case WasmOp_i32_ge_s: + case WasmOp_i32_ge_u: + case WasmOp_i64_eq: + case WasmOp_i64_ne: + case WasmOp_i64_lt_s: + case WasmOp_i64_lt_u: + case WasmOp_i64_gt_s: + case WasmOp_i64_gt_u: + case WasmOp_i64_le_s: + case WasmOp_i64_le_u: + case WasmOp_i64_ge_s: + case WasmOp_i64_ge_u: + case WasmOp_f32_eq: + case WasmOp_f32_ne: + case WasmOp_f32_lt: + case WasmOp_f32_gt: + case WasmOp_f32_le: + case WasmOp_f32_ge: + case WasmOp_f64_eq: + case WasmOp_f64_ne: + case WasmOp_f64_lt: + case WasmOp_f64_gt: + case WasmOp_f64_le: + case WasmOp_f64_ge: + case WasmOp_i32_add: + case WasmOp_i32_sub: + case WasmOp_i32_mul: + case WasmOp_i32_div_s: + case WasmOp_i32_div_u: + case WasmOp_i32_rem_s: + case WasmOp_i32_rem_u: + case WasmOp_i32_and: + case WasmOp_i32_or: + case WasmOp_i32_xor: + case WasmOp_i32_shl: + case WasmOp_i32_shr_s: + case WasmOp_i32_shr_u: + case WasmOp_i32_rotl: + case WasmOp_i32_rotr: + case WasmOp_f32_add: + case WasmOp_f32_sub: + case WasmOp_f32_mul: + case WasmOp_f32_div: + case WasmOp_f32_min: + case WasmOp_f32_max: + case WasmOp_f32_copysign: + bs_unset(stack_types, stack_depth - 1); + break; + + case WasmOp_i64_const: + case WasmOp_f64_const: + case WasmOp_i64_load: + case WasmOp_f64_load: + case WasmOp_i64_load8_s: + case WasmOp_i64_load8_u: + case WasmOp_i64_load16_s: + case WasmOp_i64_load16_u: + case WasmOp_i64_load32_s: + case WasmOp_i64_load32_u: + case WasmOp_i64_clz: + case WasmOp_i64_ctz: + case WasmOp_i64_popcnt: + case WasmOp_f64_abs: + case WasmOp_f64_neg: + case WasmOp_f64_ceil: + case WasmOp_f64_floor: + case WasmOp_f64_trunc: + case WasmOp_f64_nearest: + case WasmOp_f64_sqrt: + case WasmOp_i64_extend_i32_s: + case WasmOp_i64_extend_i32_u: + case WasmOp_i64_trunc_f32_s: + case WasmOp_i64_trunc_f32_u: + case WasmOp_i64_trunc_f64_s: + case WasmOp_i64_trunc_f64_u: + case WasmOp_f64_convert_i32_s: + case WasmOp_f64_convert_i32_u: + case WasmOp_f64_convert_i64_s: + case WasmOp_f64_convert_i64_u: + case WasmOp_f64_promote_f32: + case WasmOp_i64_reinterpret_f64: + case WasmOp_f64_reinterpret_i64: + case WasmOp_i64_extend8_s: + case WasmOp_i64_extend16_s: + case WasmOp_i64_extend32_s: + case WasmOp_i64_add: + case WasmOp_i64_sub: + case WasmOp_i64_mul: + case WasmOp_i64_div_s: + case WasmOp_i64_div_u: + case WasmOp_i64_rem_s: + case WasmOp_i64_rem_u: + case WasmOp_i64_and: + case WasmOp_i64_or: + case WasmOp_i64_xor: + case WasmOp_i64_shl: + case WasmOp_i64_shr_s: + case WasmOp_i64_shr_u: + case WasmOp_i64_rotl: + case WasmOp_i64_rotr: + case WasmOp_f64_add: + case WasmOp_f64_sub: + case WasmOp_f64_mul: + case WasmOp_f64_div: + case WasmOp_f64_min: + case WasmOp_f64_max: + case WasmOp_f64_copysign: + bs_set(stack_types, stack_depth - 1); + break; + + case WasmOp_prefixed: + switch (prefixed_opcode) { + case WasmPrefixedOp_memory_init: + case WasmPrefixedOp_memory_copy: + case WasmPrefixedOp_memory_fill: + case WasmPrefixedOp_table_init: + case WasmPrefixedOp_table_copy: + case WasmPrefixedOp_table_fill: + case WasmPrefixedOp_data_drop: + case WasmPrefixedOp_elem_drop: + break; + + case WasmPrefixedOp_i32_trunc_sat_f32_s: + case WasmPrefixedOp_i32_trunc_sat_f32_u: + case WasmPrefixedOp_i32_trunc_sat_f64_s: + case WasmPrefixedOp_i32_trunc_sat_f64_u: + case WasmPrefixedOp_table_grow: + case WasmPrefixedOp_table_size: + bs_unset(stack_types, stack_depth - 1); + break; + + case WasmPrefixedOp_i64_trunc_sat_f32_s: + case WasmPrefixedOp_i64_trunc_sat_f32_u: + case WasmPrefixedOp_i64_trunc_sat_f64_s: + case WasmPrefixedOp_i64_trunc_sat_f64_u: + bs_set(stack_types, stack_depth - 1); + break; + + default: panic("unexpected prefixed opcode"); + } + break; + + default: panic("unexpected opcode"); + } + } + + switch (opcode) { + case WasmOp_unreachable: + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_unreachable; + pc->opcode += 1; + } + break; + + case WasmOp_nop: + case WasmOp_i32_reinterpret_f32: + case WasmOp_i64_reinterpret_f64: + case WasmOp_f32_reinterpret_i32: + case WasmOp_f64_reinterpret_i64: + break; + + case WasmOp_block: + case WasmOp_loop: + case WasmOp_if: + { + int64_t block_type = read64_ileb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + label_i += 1; + struct Label *label = &labels[label_i]; + label->opcode = opcode; + if (block_type < 0) { + label->type_info.param_count = 0; + label->type_info.param_types = 0; + label->type_info.result_count = block_type != -0x40; + label->type_info.result_types = 0; + switch (block_type) { + case -0x40: break; + case -1: case -3: bs_unset(&label->type_info.param_types, 0); break; + case -2: case -4: bs_set(&label->type_info.param_types, 0); break; + default: panic("unexpected param type"); + } + } else { + label->type_info = vm->types[block_type]; + } + label->stack_depth = stack_depth - label->type_info.param_count; + label->ref_list = UINT32_MAX; + switch (opcode) { + case WasmOp_block: + break; + + case WasmOp_loop: + label->extra.loop_pc = *pc; + break; + + case WasmOp_if: + opcodes[pc->opcode] = Op_br_if_eqz_void; + pc->opcode += 1; + operands[pc->operand] = 0; + label->extra.else_ref = pc->operand + 1; + pc->operand += 3; + break; + + default: panic("unexpected label opcode"); + } + } + } + break; + + case WasmOp_else: + { + struct Label *label = &labels[label_i]; + assert(label->opcode == WasmOp_if); + label->opcode = WasmOp_else; + if (unreachable_depth == 0) { + uint32_t operand_count = Label_operandCount(label); + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_br_void; + break; + + case 1: + switch ((int)Label_operandType(label, 0)) { + case false: opcodes[pc->opcode] = Op_br_32; break; + case true: opcodes[pc->opcode] = Op_br_64; break; + } + break; + + default: panic("unexpected operand count"); + } + pc->opcode += 1; + operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 1] = label->ref_list; + label->ref_list = pc->operand + 1; + pc->operand += 3; + assert(stack_depth - label->type_info.result_count == label->stack_depth); + } else unreachable_depth = 0; + operands[label->extra.else_ref + 0] = pc->opcode; + operands[label->extra.else_ref + 1] = pc->operand; + stack_depth = label->stack_depth + label->type_info.param_count; + }; + break; + + case WasmOp_end: + if (unreachable_depth <= 1) { + unreachable_depth = 0; + struct Label *label = &labels[label_i]; + struct ProgramCounter *target_pc = (label->opcode == WasmOp_loop) ? &label->extra.loop_pc : pc; + if (label->opcode == WasmOp_if) { + operands[label->extra.else_ref + 0] = target_pc->opcode; + operands[label->extra.else_ref + 1] = target_pc->operand; + } + uint32_t ref = label->ref_list; + while (ref != UINT32_MAX) { + uint32_t next_ref = operands[ref]; + operands[ref + 0] = target_pc->opcode; + operands[ref + 1] = target_pc->operand; + ref = next_ref; + } + stack_depth = label->stack_depth + label->type_info.result_count; + + if (label_i == 0) { + uint32_t operand_count = Label_operandCount(&labels[0]); + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_return_void; + break; + + case 1: + switch ((int)Label_operandType(&labels[0], 0)) { + case false: opcodes[pc->opcode] = Op_return_32; break; + case true: opcodes[pc->opcode] = Op_return_64; break; + } + break; + + default: panic("unexpected operand count"); + } + pc->opcode += 1; + operands[pc->operand + 0] = 2 + operand_count; + stack_depth -= operand_count; + assert(stack_depth == labels[0].stack_depth); + operands[pc->operand + 1] = stack_depth; + pc->operand += 2; + return; + } + label_i -= 1; + } else unreachable_depth -= 1; + break; + + case WasmOp_br: + case WasmOp_br_if: + { + uint32_t label_idx = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + struct Label *label = &labels[label_i - label_idx]; + uint32_t operand_count = Label_operandCount(label); + switch (opcode) { + case WasmOp_br: + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_br_void; + break; + + case 1: + switch ((int)Label_operandType(label, 0)) { + case false: opcodes[pc->opcode] = Op_br_32; break; + case true: opcodes[pc->opcode] = Op_br_64; break; + } + break; + + default: panic("unexpected operand count"); + } + break; + + case WasmOp_br_if: + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_br_if_nez_void; + break; + + case 1: + switch ((int)Label_operandType(label, 0)) { + case false: opcodes[pc->opcode] = Op_br_if_nez_32; break; + case true: opcodes[pc->opcode] = Op_br_if_nez_64; break; + } + break; + + default: panic("unexpected operand count"); + } + break; + + default: panic("unexpected opcode"); + } + pc->opcode += 1; + operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 1] = label->ref_list; + label->ref_list = pc->operand + 1; + pc->operand += 3; + } + } + break; + + case WasmOp_br_table: + { + uint32_t labels_len = read32_uleb128(mod_ptr, code_i); + for (uint32_t i = 0; i <= labels_len; i += 1) { + uint32_t label_idx = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth != 0) continue; + struct Label *label = &labels[label_i - label_idx]; + uint32_t operand_count = Label_operandCount(label); + if (i == 0) { + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_br_table_void; + break; + + case 1: + switch ((int)Label_operandType(label, 0)) { + case false: opcodes[pc->opcode] = Op_br_table_32; break; + case true: opcodes[pc->opcode] = Op_br_table_64; break; + } + break; + + default: panic("unexpected operand count"); + } + pc->opcode += 1; + operands[pc->operand] = labels_len; + pc->operand += 1; + } + operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 1] = label->ref_list; + label->ref_list = pc->operand + 1; + pc->operand += 3; + } + + opcodes[pc->opcode] = opcode; + pc->opcode += 1; + operands[pc->operand] = labels_len; + pc->operand += 1; + } + break; + + case WasmOp_call: + { + uint32_t fn_id = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_call; + pc->opcode += 1; + operands[pc->operand] = fn_id; + pc->operand += 1; + uint32_t type_idx = (fn_id < vm->imports_len) ? + vm->imports[fn_id].type_idx : + vm->functions[fn_id - vm->imports_len].type_idx; + struct TypeInfo *type_info = &vm->types[type_idx]; + stack_depth -= type_info->param_count; + for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) + bs_setValue(stack_types, stack_depth + result_i, + bs_isSet(&type_info->result_types, result_i)); + stack_depth += type_info->result_count; + } + } + break; + + case WasmOp_call_indirect: + { + uint32_t type_idx = read32_uleb128(mod_ptr, code_i); + if (read32_uleb128(mod_ptr, code_i) != 0) panic("unexpected table index"); + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm; + opcodes[pc->opcode + 1] = opcode; + pc->opcode += 2; + struct TypeInfo *type_info = &vm->types[type_idx]; + stack_depth -= type_info->param_count; + for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) + bs_setValue(stack_types, stack_depth + result_i, + bs_isSet(&type_info->result_types, result_i)); + stack_depth += type_info->result_count; + } + } + break; + + case WasmOp_return: + { + uint32_t operand_count = Label_operandCount(&labels[0]); + switch (operand_count) { + case 0: + opcodes[pc->opcode] = Op_return_void; + break; + + case 1: + switch ((int)Label_operandType(&labels[0], 0)) { + case false: opcodes[pc->opcode] = Op_return_32; break; + case true: opcodes[pc->opcode] = Op_return_64; break; + } + break; + + default: panic("unexpected operand count"); + } + pc->opcode += 1; + operands[pc->operand + 0] = 2 + stack_depth - labels[0].stack_depth; + stack_depth -= operand_count; + operands[pc->operand + 1] = stack_depth; + pc->operand += 2; + } + break; + + case WasmOp_select: + case WasmOp_drop: + if (unreachable_depth == 0) { + switch ((int)bs_isSet(stack_types, stack_depth)) { + case false: + switch (opcode) { + case WasmOp_select: + opcodes[pc->opcode] = Op_select_32; + break; + + case WasmOp_drop: + opcodes[pc->opcode] = Op_drop_32; + break; + + default: panic("unexpected opcode"); + } + break; + + case true: + switch (opcode) { + case WasmOp_select: + opcodes[pc->opcode] = Op_select_64; + break; + + case WasmOp_drop: + opcodes[pc->opcode] = Op_drop_64; + break; + + default: panic("unexpected opcode"); + } + break; + } + pc->opcode += 1; + } + break; + + case WasmOp_local_get: + case WasmOp_local_set: + case WasmOp_local_tee: + { + uint32_t local_idx = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + bool local_type = bs_isSet(func->local_types, local_idx); + switch ((int)local_type) { + case false: + switch (opcode) { + case WasmOp_local_get: + opcodes[pc->opcode] = Op_local_get_32; + break; + + case WasmOp_local_set: + opcodes[pc->opcode] = Op_local_set_32; + break; + + case WasmOp_local_tee: + opcodes[pc->opcode] = Op_local_tee_32; + break; + + default: panic("unexpected opcode"); + } + break; + + case true: + switch (opcode) { + case WasmOp_local_get: + opcodes[pc->opcode] = Op_local_get_64; + break; + + case WasmOp_local_set: + opcodes[pc->opcode] = Op_local_set_64; + break; + + case WasmOp_local_tee: + opcodes[pc->opcode] = Op_local_tee_64; + break; + + default: panic("unexpected opcode"); + } + break; + } + pc->opcode += 1; + operands[pc->operand] = initial_stack_depth - local_idx; + pc->operand += 1; + if (opcode == WasmOp_local_get) bs_setValue(stack_types, stack_depth - 1, local_type); + } + } + break; + + case WasmOp_global_get: + case WasmOp_global_set: + { + uint32_t global_idx = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + switch (global_idx) { + case 0: + switch (opcode) { + case WasmOp_global_get: + opcodes[pc->opcode] = Op_global_get_0_32; + break; + + case WasmOp_global_set: + opcodes[pc->opcode] = Op_global_set_0_32; + break; + + default: panic("unexpected opcode"); + } + break; + + default: + switch (opcode) { + case WasmOp_global_get: + opcodes[pc->opcode] = Op_global_get_32; + break; + + case WasmOp_global_set: + opcodes[pc->opcode] = Op_global_set_32; + break; + + default: panic("unexpected opcode"); + } + break; + } + pc->opcode += 1; + if (global_idx != 0) { + operands[pc->operand] = global_idx; + pc->operand += 1; + } + } + } + break; + + case WasmOp_i32_load: + case WasmOp_i64_load: + case WasmOp_f32_load: + case WasmOp_f64_load: + case WasmOp_i32_load8_s: + case WasmOp_i32_load8_u: + case WasmOp_i32_load16_s: + case WasmOp_i32_load16_u: + case WasmOp_i64_load8_s: + case WasmOp_i64_load8_u: + case WasmOp_i64_load16_s: + case WasmOp_i64_load16_u: + case WasmOp_i64_load32_s: + case WasmOp_i64_load32_u: + case WasmOp_i32_store: + case WasmOp_i64_store: + case WasmOp_f32_store: + case WasmOp_f64_store: + case WasmOp_i32_store8: + case WasmOp_i32_store16: + case WasmOp_i64_store8: + case WasmOp_i64_store16: + case WasmOp_i64_store32: + { + uint32_t alignment = read32_uleb128(mod_ptr, code_i); + uint32_t offset = read32_uleb128(mod_ptr, code_i); + (void)alignment; + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm; + opcodes[pc->opcode + 1] = opcode; + pc->opcode += 2; + operands[pc->operand] = offset; + pc->operand += 1; + } + } + break; + + case WasmOp_memory_size: + case WasmOp_memory_grow: + { + if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); + *code_i += 1; + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm; + opcodes[pc->opcode + 1] = opcode; + pc->opcode += 2; + } + } + break; + + case WasmOp_i32_const: + { + uint32_t x = read32_ileb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_const_32; + pc->opcode += 1; + operands[pc->operand] = x; + pc->operand += 1; + } + } + break; + + case WasmOp_i64_const: + { + uint64_t x = read64_ileb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_const_64; + pc->opcode += 1; + operands[pc->operand + 0] = x & UINT32_MAX; + operands[pc->operand + 1] = (x >> 32) & UINT32_MAX; + pc->operand += 2; + } + } + break; + + case WasmOp_f32_const: + { + uint32_t x; + memcpy(&x, mod_ptr + *code_i, 4); + *code_i += 4; + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_const_32; + pc->opcode += 1; + operands[pc->operand] = x; + pc->operand += 1; + } + } + break; + + case WasmOp_f64_const: + { + uint64_t x; + memcpy(&x, mod_ptr + *code_i, 8); + *code_i += 8; + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_const_64; + pc->opcode += 1; + operands[pc->operand + 0] = x & UINT32_MAX; + operands[pc->operand + 1] = (x >> 32) & UINT32_MAX; + pc->operand += 2; + } + } + break; + + case WasmOp_i32_add: + opcodes[pc->opcode] = Op_add_32; + pc->opcode += 1; + break; + + case WasmOp_i32_and: + opcodes[pc->opcode] = Op_and_32; + pc->opcode += 1; + break; + + default: + opcodes[pc->opcode + 0] = Op_wasm; + opcodes[pc->opcode + 1] = opcode; + pc->opcode += 2; + break; + + case WasmOp_prefixed: + switch (prefixed_opcode) { + case WasmPrefixedOp_i32_trunc_sat_f32_s: + case WasmPrefixedOp_i32_trunc_sat_f32_u: + case WasmPrefixedOp_i32_trunc_sat_f64_s: + case WasmPrefixedOp_i32_trunc_sat_f64_u: + case WasmPrefixedOp_i64_trunc_sat_f32_s: + case WasmPrefixedOp_i64_trunc_sat_f32_u: + case WasmPrefixedOp_i64_trunc_sat_f64_s: + case WasmPrefixedOp_i64_trunc_sat_f64_u: + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm_prefixed; + opcodes[pc->opcode + 1] = prefixed_opcode; + pc->opcode += 2; + } + break; + + case WasmPrefixedOp_memory_copy: + if (mod_ptr[*code_i + 0] != 0 || mod_ptr[*code_i + 1] != 0) + panic("unexpected memory index"); + *code_i += 2; + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm_prefixed; + opcodes[pc->opcode + 1] = prefixed_opcode; + pc->opcode += 2; + } + break; + + case WasmPrefixedOp_memory_fill: + if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); + *code_i += 1; + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm_prefixed; + opcodes[pc->opcode + 1] = prefixed_opcode; + pc->opcode += 2; + } + break; + + default: panic("unreachable"); + } + break; + } + + switch (opcode) { + case WasmOp_unreachable: + case WasmOp_return: + case WasmOp_br: + case WasmOp_br_table: + if (unreachable_depth == 0) unreachable_depth = 1; + break; + + default: + break; + } + } +} + +static void vm_push_u32(struct VirtualMachine *vm, uint32_t value) { + vm->stack[vm->stack_top] = value; + vm->stack_top += 1; +} + +static void vm_push_i32(struct VirtualMachine *vm, int32_t value) { + return vm_push_u32(vm, value); +} + +static void vm_push_u64(struct VirtualMachine *vm, uint64_t value) { + vm->stack[vm->stack_top] = value; + vm->stack_top += 1; +} + +static void vm_push_i64(struct VirtualMachine *vm, int64_t value) { + return vm_push_u64(vm, value); +} + +static void vm_push_f32(struct VirtualMachine *vm, float value) { + uint32_t integer; + memcpy(&integer, &value, 4); + return vm_push_u32(vm, integer); +} + +static void vm_push_f64(struct VirtualMachine *vm, double value) { + uint64_t integer; + memcpy(&integer, &value, 8); + return vm_push_u64(vm, integer); +} + +static uint32_t vm_pop_u32(struct VirtualMachine *vm) { + vm->stack_top -= 1; + return vm->stack[vm->stack_top]; +} + +static int32_t vm_pop_i32(struct VirtualMachine *vm) { + return vm_pop_u32(vm); +} + +static uint64_t vm_pop_u64(struct VirtualMachine *vm) { + vm->stack_top -= 1; + return vm->stack[vm->stack_top]; +} + +static int64_t vm_pop_i64(struct VirtualMachine *vm) { + return vm_pop_u64(vm); +} + +static float vm_pop_f32(struct VirtualMachine *vm) { + uint32_t integer = vm_pop_u32(vm); + float result; + memcpy(&result, &integer, 4); + return result; +} + +static double vm_pop_f64(struct VirtualMachine *vm) { + uint32_t integer = vm_pop_u64(vm); + double result; + memcpy(&result, &integer, 8); + return result; +} + +static void vm_callImport(struct VirtualMachine *vm, struct Import import) { + switch (import.mod) { + case ImpMod_wasi_snapshot_preview1: switch (import.name) { + case ImpName_fd_prestat_get: + { + uint32_t buf = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_prestat_get(vm, fd, buf)); + } + break; + case ImpName_fd_prestat_dir_name: + { + uint32_t path_len = vm_pop_u32(vm); + uint32_t path = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_prestat_dir_name(vm, fd, path, path_len)); + } + break; + case ImpName_fd_close: + { + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_close(vm, fd)); + } + break; + case ImpName_fd_read: + { + uint32_t nread = vm_pop_u32(vm); + uint32_t iovs_len = vm_pop_u32(vm); + uint32_t iovs = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_read(vm, fd, iovs, iovs_len, nread)); + } + break; + case ImpName_fd_filestat_get: + { + uint32_t buf = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_filestat_get(vm, fd, buf)); + } + break; + case ImpName_fd_filestat_set_size: + { + uint64_t size = vm_pop_u64(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_filestat_set_size(vm, fd, size)); + } + break; + case ImpName_fd_filestat_set_times: + { + panic("unexpected call to fd_filestat_set_times"); + } + break; + case ImpName_fd_fdstat_get: + { + uint32_t buf = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_fdstat_get(vm, fd, buf)); + } + break; + case ImpName_fd_readdir: + { + panic("TODO implement fd_readdir"); + } + break; + case ImpName_fd_write: + { + uint32_t nwritten = vm_pop_u32(vm); + uint32_t iovs_len = vm_pop_u32(vm); + uint32_t iovs = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_write(vm, fd, iovs, iovs_len, nwritten)); + } + break; + case ImpName_fd_pwrite: + { + uint32_t nwritten = vm_pop_u32(vm); + uint64_t offset = vm_pop_u64(vm); + uint32_t iovs_len = vm_pop_u32(vm); + uint32_t iovs = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_fd_pwrite(vm, fd, iovs, iovs_len, offset, nwritten)); + } + break; + case ImpName_proc_exit: + { + uint32_t code = vm_pop_u32(vm); + exit(code); + } + break; + case ImpName_args_sizes_get: + { + uint32_t argv_buf_size = vm_pop_u32(vm); + uint32_t argc = vm_pop_u32(vm); + vm_push_u32(vm, wasi_args_sizes_get(vm, argc, argv_buf_size)); + } + break; + case ImpName_args_get: + { + uint32_t argv_buf = vm_pop_u32(vm); + uint32_t argv = vm_pop_u32(vm); + vm_push_u32(vm, wasi_args_get(vm, argv, argv_buf)); + } + break; + case ImpName_random_get: + { + uint32_t buf_len = vm_pop_u32(vm); + uint32_t buf = vm_pop_u32(vm); + vm_push_u32(vm, wasi_random_get(vm, buf, buf_len)); + } + break; + case ImpName_environ_sizes_get: + { + panic("unexpected call to environ_sizes_get"); + } + break; + case ImpName_environ_get: + { + panic("unexpected call to environ_get"); + } + break; + case ImpName_path_filestat_get: + { + uint32_t buf = vm_pop_u32(vm); + uint32_t path_len = vm_pop_u32(vm); + uint32_t path = vm_pop_u32(vm); + uint32_t flags = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_path_filestat_get(vm, fd, flags, path, path_len, buf)); + } + break; + case ImpName_path_create_directory: + { + uint32_t path_len = vm_pop_u32(vm); + uint32_t path = vm_pop_u32(vm); + int32_t fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_path_create_directory(vm, fd, path, path_len)); + } + break; + case ImpName_path_rename: + { + uint32_t new_path_len = vm_pop_u32(vm); + uint32_t new_path = vm_pop_u32(vm); + int32_t new_fd = vm_pop_i32(vm); + uint32_t old_path_len = vm_pop_u32(vm); + uint32_t old_path = vm_pop_u32(vm); + int32_t old_fd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_path_rename( + vm, + old_fd, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len + )); + } + break; + case ImpName_path_open: + { + uint32_t fd = vm_pop_u32(vm); + uint32_t fs_flags = vm_pop_u32(vm); + uint64_t fs_rights_inheriting = vm_pop_u64(vm); + uint64_t fs_rights_base = vm_pop_u64(vm); + uint32_t oflags = vm_pop_u32(vm); + uint32_t path_len = vm_pop_u32(vm); + uint32_t path = vm_pop_u32(vm); + uint32_t dirflags = vm_pop_u32(vm); + int32_t dirfd = vm_pop_i32(vm); + vm_push_u32(vm, wasi_path_open( + vm, + dirfd, + dirflags, + path, + path_len, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd + )); + } + break; + case ImpName_path_remove_directory: + { + panic("unexpected call to path_remove_directory"); + } + break; + case ImpName_path_unlink_file: + { + panic("unexpected call to path_unlink_file"); + } + break; + case ImpName_clock_time_get: + { + uint32_t timestamp = vm_pop_u32(vm); + uint64_t precision = vm_pop_u64(vm); + uint32_t clock_id = vm_pop_u32(vm); + vm_push_u32(vm, wasi_clock_time_get(vm, clock_id, precision, timestamp)); + } + break; + case ImpName_fd_pread: + { + panic("unexpected call to fd_pread"); + } + break; + case ImpName_debug: + { + uint64_t number = vm_pop_u64(vm); + uint32_t text = vm_pop_u32(vm); + wasi_debug(vm, text, number); + } + break; + case ImpName_debug_slice: + { + uint32_t len = vm_pop_u32(vm); + uint32_t ptr = vm_pop_u32(vm); + wasi_debug_slice(vm, ptr, len); + } + break; + } + break; + } +} + +static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) { + if (fn_id < vm->imports_len) { + struct Import imp = vm->imports[fn_id]; + return vm_callImport(vm, imp); + } + uint32_t fn_idx = fn_id - vm->imports_len; + struct Function *func = &vm->functions[fn_idx]; + + // Push zeroed locals to stack + memset(&vm->stack[vm->stack_top], 0, func->locals_count * sizeof(uint64_t)); + vm->stack_top += func->locals_count; + + vm_push_u32(vm, vm->pc.opcode); + vm_push_u32(vm, vm->pc.operand); + + vm->pc = func->entry_pc; +} + +static void vm_br_void(struct VirtualMachine *vm) { + uint32_t stack_adjust = vm->operands[vm->pc.operand]; + + vm->stack_top -= stack_adjust; + + vm->pc.opcode = vm->operands[vm->pc.operand + 1]; + vm->pc.operand = vm->operands[vm->pc.operand + 2]; +} + +static void vm_br_u32(struct VirtualMachine *vm) { + uint32_t stack_adjust = vm->operands[vm->pc.operand]; + + uint32_t result = vm_pop_u32(vm); + vm->stack_top -= stack_adjust; + vm_push_u32(vm, result); + + vm->pc.opcode = vm->operands[vm->pc.operand + 1]; + vm->pc.operand = vm->operands[vm->pc.operand + 2]; +} + +static void vm_br_u64(struct VirtualMachine *vm) { + uint32_t stack_adjust = vm->operands[vm->pc.operand]; + + uint64_t result = vm_pop_u64(vm); + vm->stack_top -= stack_adjust; + vm_push_u64(vm, result); + + vm->pc.opcode = vm->operands[vm->pc.operand + 1]; + vm->pc.operand = vm->operands[vm->pc.operand + 2]; +} + +static void vm_return_void(struct VirtualMachine *vm) { + uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; + + vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; + vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + + vm->stack_top -= stack_adjust; +} + +static void vm_return_u32(struct VirtualMachine *vm) { + uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; + + vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; + vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + + uint32_t result = vm_pop_u32(vm); + vm->stack_top -= stack_adjust; + vm_push_u32(vm, result); +} + +static void vm_return_u64(struct VirtualMachine *vm) { + uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; + + vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; + vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + + uint64_t result = vm_pop_u64(vm); + vm->stack_top -= stack_adjust; + vm_push_u64(vm, result); +} + +static void vm_run(struct VirtualMachine *vm) { + uint8_t *opcodes = vm->opcodes; + uint32_t *operands = vm->operands; + struct ProgramCounter *pc = &vm->pc; + for (;;) { + enum Op op = opcodes[pc->opcode]; + pc->opcode += 1; + switch (op) { + case Op_unreachable: + panic("unreachable reached"); + + case Op_br_void: + vm_br_void(vm); + break; + + case Op_br_32: + vm_br_u32(vm); + break; + + case Op_br_64: + vm_br_u64(vm); + break; + + case Op_br_if_nez_void: + if (vm_pop_u32(vm) != 0) { + vm_br_void(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_if_nez_32: + if (vm_pop_u32(vm) != 0) { + vm_br_u32(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_if_nez_64: + if (vm_pop_u32(vm) != 0) { + vm_br_u64(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_if_eqz_void: + if (vm_pop_u32(vm) == 0) { + vm_br_void(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_if_eqz_32: + if (vm_pop_u32(vm) == 0) { + vm_br_u32(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_if_eqz_64: + if (vm_pop_u32(vm) == 0) { + vm_br_u64(vm); + } else { + pc->operand += 3; + } + break; + + case Op_br_table_void: + { + uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); + pc->operand += 1 + index * 3; + vm_br_void(vm); + } + break; + + case Op_br_table_32: + { + uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); + pc->operand += 1 + index * 3; + vm_br_u32(vm); + } + break; + + case Op_br_table_64: + { + uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); + pc->operand += 1 + index * 3; + vm_br_u64(vm); + } + break; + + case Op_return_void: + vm_return_void(vm); + break; + + case Op_return_32: + vm_return_u32(vm); + break; + + case Op_return_64: + vm_return_u64(vm); + break; + + case Op_call: + { + uint32_t fn_id = operands[pc->operand]; + pc->operand += 1; + vm_call(vm, fn_id); + } + break; + + case Op_drop_32: + case Op_drop_64: + vm->stack_top -= 1; + break; + + case Op_select_32: + { + uint32_t c = vm_pop_u32(vm); + uint32_t b = vm_pop_u32(vm); + uint32_t a = vm_pop_u32(vm); + uint32_t result = (c != 0) ? a : b; + vm_push_u32(vm, result); + } + break; + + case Op_select_64: + { + uint32_t c = vm_pop_u32(vm); + uint64_t b = vm_pop_u64(vm); + uint64_t a = vm_pop_u64(vm); + uint64_t result = (c != 0) ? a : b; + vm_push_u64(vm, result); + } + break; + + case Op_local_get_32: + { + uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + vm_push_u32(vm, *local); + } + break; + + case Op_local_get_64: + { + uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + vm_push_u64(vm, *local); + } + break; + + case Op_local_set_32: + { + uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + *local = vm_pop_u32(vm); + } + break; + + case Op_local_set_64: + { + uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + *local = vm_pop_u64(vm); + } + break; + + case Op_local_tee_32: + case Op_local_tee_64: + { + uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + *local = vm->stack[vm->stack_top - 1]; + } + break; + + case Op_global_get_0_32: + vm_push_u32(vm, vm->globals[0]); + break; + + case Op_global_get_32: + { + uint32_t idx = operands[pc->operand]; + pc->operand += 1; + vm_push_u32(vm, vm->globals[idx]); + } + break; + + case Op_global_set_0_32: + vm->globals[0] = vm_pop_u32(vm); + break; + + case Op_global_set_32: + { + uint32_t idx = operands[pc->operand]; + pc->operand += 1; + vm->globals[idx] = vm_pop_u32(vm); + } + break; + + case Op_const_32: + { + uint32_t x = operands[pc->operand]; + pc->operand += 1; + vm_push_i32(vm, x); + } + break; + + case Op_const_64: + { + uint64_t x = ((uint64_t)operands[pc->operand]) | + (((uint64_t)operands[pc->operand + 1]) << 32); + pc->operand += 2; + vm_push_i64(vm, x); + } + break; + + case Op_add_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs + rhs); + } + break; + + case Op_and_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs & rhs); + } + break; + + case Op_wasm: + { + enum WasmOp wasm_op = opcodes[pc->opcode]; + pc->opcode += 1; + switch (wasm_op) { + case WasmOp_unreachable: + case WasmOp_nop: + case WasmOp_block: + case WasmOp_loop: + case WasmOp_if: + case WasmOp_else: + case WasmOp_end: + case WasmOp_br: + case WasmOp_br_if: + case WasmOp_br_table: + case WasmOp_return: + case WasmOp_call: + case WasmOp_drop: + case WasmOp_select: + case WasmOp_local_get: + case WasmOp_local_set: + case WasmOp_local_tee: + case WasmOp_global_get: + case WasmOp_global_set: + case WasmOp_i32_const: + case WasmOp_i64_const: + case WasmOp_f32_const: + case WasmOp_f64_const: + case WasmOp_i32_add: + case WasmOp_i32_and: + case WasmOp_i32_reinterpret_f32: + case WasmOp_i64_reinterpret_f64: + case WasmOp_f32_reinterpret_i32: + case WasmOp_f64_reinterpret_i64: + case WasmOp_prefixed: + panic("not produced by decodeCode"); + break; + + case WasmOp_call_indirect: + { + uint32_t fn_id = vm->table[vm_pop_u32(vm)]; + vm_call(vm, fn_id); + } + break; + case WasmOp_i32_load: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_u32(vm, read_u32_le(vm->memory + offset)); + } + break; + case WasmOp_i64_load: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_u64(vm, read_u64_le(vm->memory + offset)); + } + break; + case WasmOp_f32_load: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + uint32_t integer = read_u32_le(vm->memory + offset); + vm_push_u32(vm, integer); + } + break; + case WasmOp_f64_load: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + uint64_t integer = read_u64_le(vm->memory + offset); + vm_push_u64(vm, integer); + } + break; + case WasmOp_i32_load8_s: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_i32(vm, (int8_t)vm->memory[offset]); + } + break; + case WasmOp_i32_load8_u: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_u32(vm, vm->memory[offset]); + } + break; + case WasmOp_i32_load16_s: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + int16_t integer = read_i16_le(vm->memory + offset); + vm_push_i32(vm, integer); + } + break; + case WasmOp_i32_load16_u: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + uint16_t integer = read_u16_le(vm->memory + offset); + vm_push_u32(vm, integer); + } + break; + case WasmOp_i64_load8_s: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_i64(vm, (int8_t)vm->memory[offset]); + } + break; + case WasmOp_i64_load8_u: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm_push_u64(vm, vm->memory[offset]); + } + break; + case WasmOp_i64_load16_s: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + int16_t integer = read_i16_le(vm->memory + offset); + vm_push_i64(vm, integer); + } + break; + case WasmOp_i64_load16_u: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + uint16_t integer = read_u16_le(vm->memory + offset); + vm_push_u64(vm, integer); + } + break; + case WasmOp_i64_load32_s: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + int32_t integer = read_i32_le(vm->memory + offset); + vm_push_i64(vm, integer); + } + break; + case WasmOp_i64_load32_u: + { + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + uint32_t integer = read_u32_le(vm->memory + offset); + vm_push_u64(vm, integer); + } + break; + case WasmOp_i32_store: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u32_le(vm->memory + offset, operand); + } + break; + case WasmOp_i64_store: + { + uint64_t operand = vm_pop_u64(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u64_le(vm->memory + offset, operand); + } + break; + case WasmOp_f32_store: + { + uint32_t integer = vm_pop_u32(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u32_le(vm->memory + offset, integer); + } + break; + case WasmOp_f64_store: + { + uint64_t integer = vm_pop_u64(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u64_le(vm->memory + offset, integer); + } + break; + case WasmOp_i32_store8: + { + uint8_t small = vm_pop_u32(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm->memory[offset] = small; + } + break; + case WasmOp_i32_store16: + { + uint16_t small = vm_pop_u32(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u16_le(vm->memory + offset, small); + } + break; + case WasmOp_i64_store8: + { + uint8_t operand = vm_pop_u64(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + vm->memory[offset] = operand; + } + break; + case WasmOp_i64_store16: + { + uint16_t small = vm_pop_u64(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u16_le(vm->memory + offset, small); + } + break; + case WasmOp_i64_store32: + { + uint32_t small = vm_pop_u64(vm); + uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); + pc->operand += 1; + write_u32_le(vm->memory + offset, small); + } + break; + case WasmOp_memory_size: + { + uint32_t page_count = vm->memory_len / wasm_page_size; + vm_push_u32(vm, page_count); + } + break; + case WasmOp_memory_grow: + { + uint32_t page_count = vm_pop_u32(vm); + uint32_t old_page_count = vm->memory_len / wasm_page_size; + uint32_t new_len = vm->memory_len + page_count * wasm_page_size; + if (new_len > vm->memory_len) { + vm_push_i32(vm, -1); + } else { + vm->memory_len = new_len; + vm_push_u32(vm, old_page_count); + } + } + break; + case WasmOp_i32_eqz: + { + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs == 0); + } + break; + case WasmOp_i32_eq: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case WasmOp_i32_ne: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case WasmOp_i32_lt_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case WasmOp_i32_lt_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case WasmOp_i32_gt_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_i32_gt_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_i32_le_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_i32_le_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_i32_ge_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case WasmOp_i32_ge_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case WasmOp_i64_eqz: + { + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs == 0); + } + break; + case WasmOp_i64_eq: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case WasmOp_i64_ne: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case WasmOp_i64_lt_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case WasmOp_i64_lt_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case WasmOp_i64_gt_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_i64_gt_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_i64_le_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_i64_le_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_i64_ge_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case WasmOp_i64_ge_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case WasmOp_f32_eq: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case WasmOp_f32_ne: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case WasmOp_f32_lt: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case WasmOp_f32_gt: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_f32_le: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_f32_ge: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case WasmOp_f64_eq: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case WasmOp_f64_ne: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case WasmOp_f64_lt: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_f64_gt: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case WasmOp_f64_le: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case WasmOp_f64_ge: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + + case WasmOp_i32_clz: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand); + vm_push_u32(vm, result); + } + break; + case WasmOp_i32_ctz: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand); + vm_push_u32(vm, result); + } + break; + case WasmOp_i32_popcnt: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = __builtin_popcount(operand); + vm_push_u32(vm, result); + } + break; + case WasmOp_i32_sub: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs - rhs); + } + break; + case WasmOp_i32_mul: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs * rhs); + } + break; + case WasmOp_i32_div_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs / rhs); + } + break; + case WasmOp_i32_div_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs / rhs); + } + break; + case WasmOp_i32_rem_s: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs % rhs); + } + break; + case WasmOp_i32_rem_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs % rhs); + } + break; + case WasmOp_i32_or: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs | rhs); + } + break; + case WasmOp_i32_xor: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs ^ rhs); + } + break; + case WasmOp_i32_shl: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs << rhs); + } + break; + case WasmOp_i32_shr_s: + { + uint32_t rhs = vm_pop_u32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs >> rhs); + } + break; + case WasmOp_i32_shr_u: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs >> rhs); + } + break; + case WasmOp_i32_rotl: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, rotl32(lhs, rhs)); + } + break; + case WasmOp_i32_rotr: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, rotr32(lhs, rhs )); + } + break; + + case WasmOp_i64_clz: + { + uint64_t operand = vm_pop_u64(vm); + uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand); + vm_push_u64(vm, result); + } + break; + case WasmOp_i64_ctz: + { + uint64_t operand = vm_pop_u64(vm); + uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand); + vm_push_u64(vm, result); + } + break; + case WasmOp_i64_popcnt: + { + uint64_t operand = vm_pop_u64(vm); + uint64_t result = __builtin_popcountll(operand); + vm_push_u64(vm, result); + } + break; + case WasmOp_i64_add: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs + rhs); + } + break; + case WasmOp_i64_sub: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs - rhs); + } + break; + case WasmOp_i64_mul: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs * rhs); + } + break; + case WasmOp_i64_div_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs / rhs); + } + break; + case WasmOp_i64_div_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs / rhs); + } + break; + case WasmOp_i64_rem_s: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs % rhs); + } + break; + case WasmOp_i64_rem_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs % rhs); + } + break; + case WasmOp_i64_and: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs & rhs); + } + break; + case WasmOp_i64_or: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs | rhs); + } + break; + case WasmOp_i64_xor: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs ^ rhs); + } + break; + case WasmOp_i64_shl: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs << rhs); + } + break; + case WasmOp_i64_shr_s: + { + uint64_t rhs = vm_pop_u64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs >> rhs); + } + break; + case WasmOp_i64_shr_u: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs >> rhs); + } + break; + case WasmOp_i64_rotl: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, rotl64(lhs, rhs )); + } + break; + case WasmOp_i64_rotr: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, rotr64(lhs, rhs )); + } + break; + + case WasmOp_f32_abs: + { + vm_push_f32(vm, fabsf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_neg: + { + vm_push_f32(vm, -vm_pop_f32(vm)); + } + break; + case WasmOp_f32_ceil: + { + vm_push_f32(vm, ceilf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_floor: + { + vm_push_f32(vm, floorf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_trunc: + { + vm_push_f32(vm, truncf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_nearest: + { + vm_push_f32(vm, roundf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_sqrt: + { + vm_push_f32(vm, sqrtf(vm_pop_f32(vm))); + } + break; + case WasmOp_f32_add: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs + rhs); + } + break; + case WasmOp_f32_sub: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs - rhs); + } + break; + case WasmOp_f32_mul: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs * rhs); + } + break; + case WasmOp_f32_div: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs / rhs); + } + break; + case WasmOp_f32_min: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, (lhs < rhs) ? lhs : rhs); + } + break; + case WasmOp_f32_max: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, (lhs > rhs) ? lhs : rhs); + } + break; + case WasmOp_f32_copysign: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, copysignf(lhs, rhs)); + } + break; + case WasmOp_f64_abs: + { + vm_push_f64(vm, fabs(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_neg: + { + vm_push_f64(vm, -vm_pop_f64(vm)); + } + break; + case WasmOp_f64_ceil: + { + vm_push_f64(vm, ceil(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_floor: + { + vm_push_f64(vm, floor(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_trunc: + { + vm_push_f64(vm, trunc(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_nearest: + { + vm_push_f64(vm, round(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_sqrt: + { + vm_push_f64(vm, sqrt(vm_pop_f64(vm))); + } + break; + case WasmOp_f64_add: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs + rhs); + } + break; + case WasmOp_f64_sub: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs - rhs); + } + break; + case WasmOp_f64_mul: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs * rhs); + } + break; + case WasmOp_f64_div: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs / rhs); + } + break; + case WasmOp_f64_min: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, (lhs < rhs) ? lhs : rhs); + } + break; + case WasmOp_f64_max: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, (lhs > rhs) ? lhs : rhs); + } + break; + case WasmOp_f64_copysign: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, copysign(lhs, rhs)); + } + break; + + case WasmOp_i32_wrap_i64: + { + uint64_t operand = vm_pop_u64(vm); + vm_push_u32(vm, operand); + } + break; + case WasmOp_i32_trunc_f32_s: + { + float operand = vm_pop_f32(vm); + vm_push_i32(vm, truncf(operand)); + } + break; + case WasmOp_i32_trunc_f32_u: + { + float operand = vm_pop_f32(vm); + vm_push_u32(vm, truncf(operand)); + } + break; + case WasmOp_i32_trunc_f64_s: + { + double operand = vm_pop_f64(vm); + vm_push_i32(vm, trunc(operand)); + } + break; + case WasmOp_i32_trunc_f64_u: + { + double operand = vm_pop_f64(vm); + vm_push_u32(vm, trunc(operand)); + } + break; + case WasmOp_i64_extend_i32_s: + { + int32_t operand = vm_pop_i32(vm); + vm_push_i64(vm, operand); + } + break; + case WasmOp_i64_extend_i32_u: + { + uint64_t operand = vm_pop_u64(vm); + vm_push_u64(vm, operand); + } + break; + case WasmOp_i64_trunc_f32_s: + { + float operand = vm_pop_f32(vm); + vm_push_i64(vm, truncf(operand)); + } + break; + case WasmOp_i64_trunc_f32_u: + { + float operand = vm_pop_f32(vm); + vm_push_u64(vm, truncf(operand)); + } + break; + case WasmOp_i64_trunc_f64_s: + { + double operand = vm_pop_f64(vm); + vm_push_i64(vm, trunc(operand)); + } + break; + case WasmOp_i64_trunc_f64_u: + { + double operand = vm_pop_f64(vm); + vm_push_u64(vm, trunc(operand)); + } + break; + case WasmOp_f32_convert_i32_s: + { + vm_push_f32(vm, vm_pop_i32(vm)); + } + break; + case WasmOp_f32_convert_i32_u: + { + vm_push_f32(vm, vm_pop_u32(vm)); + } + break; + case WasmOp_f32_convert_i64_s: + { + vm_push_f32(vm, vm_pop_i64(vm)); + } + break; + case WasmOp_f32_convert_i64_u: + { + vm_push_f32(vm, vm_pop_u64(vm)); + } + break; + case WasmOp_f32_demote_f64: + { + vm_push_f32(vm, vm_pop_f64(vm)); + } + break; + case WasmOp_f64_convert_i32_s: + { + vm_push_f64(vm, vm_pop_i32(vm)); + } + break; + case WasmOp_f64_convert_i32_u: + { + vm_push_f64(vm, vm_pop_u32(vm)); + } + break; + case WasmOp_f64_convert_i64_s: + { + vm_push_f64(vm, vm_pop_i64(vm)); + } + break; + case WasmOp_f64_convert_i64_u: + { + vm_push_f64(vm, vm_pop_u64(vm)); + } + break; + case WasmOp_f64_promote_f32: + { + vm_push_f64(vm, vm_pop_f32(vm)); + } + break; + + case WasmOp_i32_extend8_s: + { + int8_t operand = vm_pop_i32(vm); + vm_push_i32(vm, operand); + } + break; + case WasmOp_i32_extend16_s: + { + int16_t operand = vm_pop_i32(vm); + vm_push_i32(vm, operand); + } + break; + case WasmOp_i64_extend8_s: + { + int8_t operand = vm_pop_i64(vm); + vm_push_i64(vm, operand); + } + break; + case WasmOp_i64_extend16_s: + { + int16_t operand = vm_pop_i64(vm); + vm_push_i64(vm, operand); + } + break; + case WasmOp_i64_extend32_s: + { + int32_t operand = vm_pop_i64(vm); + vm_push_i64(vm, operand); + } + break; + + default: + panic("unreachable"); + } + } + break; + + case Op_wasm_prefixed: + { + enum WasmPrefixedOp wasm_prefixed_op = opcodes[pc->opcode]; + pc->opcode += 1; + switch (wasm_prefixed_op) { + case WasmPrefixedOp_i32_trunc_sat_f32_s: + panic("unreachable"); + case WasmPrefixedOp_i32_trunc_sat_f32_u: + panic("unreachable"); + case WasmPrefixedOp_i32_trunc_sat_f64_s: + panic("unreachable"); + case WasmPrefixedOp_i32_trunc_sat_f64_u: + panic("unreachable"); + case WasmPrefixedOp_i64_trunc_sat_f32_s: + panic("unreachable"); + case WasmPrefixedOp_i64_trunc_sat_f32_u: + panic("unreachable"); + case WasmPrefixedOp_i64_trunc_sat_f64_s: + panic("unreachable"); + case WasmPrefixedOp_i64_trunc_sat_f64_u: + panic("unreachable"); + case WasmPrefixedOp_memory_init: + panic("unreachable"); + case WasmPrefixedOp_data_drop: + panic("unreachable"); + + case WasmPrefixedOp_memory_copy: + { + uint32_t n = vm_pop_u32(vm); + uint32_t src = vm_pop_u32(vm); + uint32_t dest = vm_pop_u32(vm); + assert(dest + n <= vm->memory_len); + assert(src + n <= vm->memory_len); + assert(src + n <= dest || dest + n <= src); // overlapping + memcpy(vm->memory + dest, vm->memory + src, n); + } + break; + + case WasmPrefixedOp_memory_fill: + { + uint32_t n = vm_pop_u32(vm); + uint8_t value = vm_pop_u32(vm); + uint32_t dest = vm_pop_u32(vm); + assert(dest + n <= vm->memory_len); + memset(vm->memory + dest, value, n); + } + break; + + case WasmPrefixedOp_table_init: panic("unreachable"); + case WasmPrefixedOp_elem_drop: panic("unreachable"); + case WasmPrefixedOp_table_copy: panic("unreachable"); + case WasmPrefixedOp_table_grow: panic("unreachable"); + case WasmPrefixedOp_table_size: panic("unreachable"); + case WasmPrefixedOp_table_fill: panic("unreachable"); + default: panic("unreachable"); + } + } + break; + + } + } +} + +int main(int argc, char **argv) { + char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + + const char *zig_lib_dir_path = argv[1]; + const char *zig_cache_dir_path = argv[2]; + const size_t vm_argv_start = 3; + const char *wasm_file = argv[vm_argv_start]; + + const struct ByteSlice mod = read_file_alloc(wasm_file); + + int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + mkdir(zig_cache_dir_path, 0666); + int cache_dir = err_wrap("opening cache dir", open(zig_cache_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + + add_preopen(0, "stdin", STDIN_FILENO); + add_preopen(1, "stdout", STDOUT_FILENO); + add_preopen(2, "stderr", STDERR_FILENO); + add_preopen(3, ".", cwd); + add_preopen(4, "/cache", cache_dir); + add_preopen(5, "/lib", zig_lib_dir); + + uint32_t i = 0; + + if (mod.ptr[0] != 0 || mod.ptr[1] != 'a' || mod.ptr[2] != 's' || mod.ptr[3] != 'm') { + panic("bad magic"); + } + i += 4; + + uint32_t version = read_u32_le(mod.ptr + i); + i += 4; + if (version != 1) panic("bad wasm version"); + + uint32_t section_starts[13]; + memset(§ion_starts, 0, 4 * 13); + + while (i < mod.len) { + uint8_t section_id = mod.ptr[i]; + i += 1; + uint32_t section_len = read32_uleb128(mod.ptr, &i); + section_starts[section_id] = i; + i += section_len; + } + + // Map type indexes to offsets into the module. + struct TypeInfo *types; + { + i = section_starts[Section_type]; + uint32_t types_len = read32_uleb128(mod.ptr, &i); + types = arena_alloc(sizeof(struct TypeInfo) * types_len); + for (size_t type_i = 0; type_i < types_len; type_i += 1) { + struct TypeInfo *info = &types[type_i]; + if (mod.ptr[i] != 0x60) panic("bad type byte"); + i += 1; + + info->param_count = read32_uleb128(mod.ptr, &i); + info->param_types = 0; + for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { + int64_t param_type = read64_ileb128(mod.ptr, &i); + switch (param_type) { + case -1: case -3: bs_unset(&info->param_types, param_i); break; + case -2: case -4: bs_set(&info->param_types, param_i); break; + default: panic("unexpected param type"); + } + } + + info->result_count = read32_uleb128(mod.ptr, &i); + info->result_types = 0; + for (uint32_t result_i = 0; result_i < info->result_count; result_i += 1) { + int64_t result_type = read64_ileb128(mod.ptr, &i); + switch (result_type) { + case -1: case -3: bs_unset(&info->result_types, result_i); break; + case -2: case -4: bs_set(&info->result_types, result_i); break; + default: panic("unexpected result type"); + } + } + } + } + + // Count the imported functions so we can correct function references. + struct Import *imports; + uint32_t imports_len; + { + i = section_starts[Section_import]; + imports_len = read32_uleb128(mod.ptr, &i); + imports = arena_alloc(sizeof(struct Import) * imports_len); + for (size_t imp_i = 0; imp_i < imports_len; imp_i += 1) { + struct Import *imp = &imports[imp_i]; + + struct ByteSlice mod_name = read_name(mod.ptr, &i); + if (mod_name.len == strlen("wasi_snapshot_preview1") && + memcmp(mod_name.ptr, "wasi_snapshot_preview1", mod_name.len) == 0) { + imp->mod = ImpMod_wasi_snapshot_preview1; + } else panic("unknown import module"); + + struct ByteSlice sym_name = read_name(mod.ptr, &i); + if (sym_name.len == strlen("args_get") && + memcmp(sym_name.ptr, "args_get", sym_name.len) == 0) { + imp->name = ImpName_args_get; + } else if (sym_name.len == strlen("args_sizes_get") && + memcmp(sym_name.ptr, "args_sizes_get", sym_name.len) == 0) { + imp->name = ImpName_args_sizes_get; + } else if (sym_name.len == strlen("clock_time_get") && + memcmp(sym_name.ptr, "clock_time_get", sym_name.len) == 0) { + imp->name = ImpName_clock_time_get; + } else if (sym_name.len == strlen("debug") && + memcmp(sym_name.ptr, "debug", sym_name.len) == 0) { + imp->name = ImpName_debug; + } else if (sym_name.len == strlen("debug_slice") && + memcmp(sym_name.ptr, "debug_slice", sym_name.len) == 0) { + imp->name = ImpName_debug_slice; + } else if (sym_name.len == strlen("environ_get") && + memcmp(sym_name.ptr, "environ_get", sym_name.len) == 0) { + imp->name = ImpName_environ_get; + } else if (sym_name.len == strlen("environ_sizes_get") && + memcmp(sym_name.ptr, "environ_sizes_get", sym_name.len) == 0) { + imp->name = ImpName_environ_sizes_get; + } else if (sym_name.len == strlen("fd_close") && + memcmp(sym_name.ptr, "fd_close", sym_name.len) == 0) { + imp->name = ImpName_fd_close; + } else if (sym_name.len == strlen("fd_fdstat_get") && + memcmp(sym_name.ptr, "fd_fdstat_get", sym_name.len) == 0) { + imp->name = ImpName_fd_fdstat_get; + } else if (sym_name.len == strlen("fd_filestat_get") && + memcmp(sym_name.ptr, "fd_filestat_get", sym_name.len) == 0) { + imp->name = ImpName_fd_filestat_get; + } else if (sym_name.len == strlen("fd_filestat_set_size") && + memcmp(sym_name.ptr, "fd_filestat_set_size", sym_name.len) == 0) { + imp->name = ImpName_fd_filestat_set_size; + } else if (sym_name.len == strlen("fd_filestat_set_times") && + memcmp(sym_name.ptr, "fd_filestat_set_times", sym_name.len) == 0) { + imp->name = ImpName_fd_filestat_set_times; + } else if (sym_name.len == strlen("fd_pread") && + memcmp(sym_name.ptr, "fd_pread", sym_name.len) == 0) { + imp->name = ImpName_fd_pread; + } else if (sym_name.len == strlen("fd_prestat_dir_name") && + memcmp(sym_name.ptr, "fd_prestat_dir_name", sym_name.len) == 0) { + imp->name = ImpName_fd_prestat_dir_name; + } else if (sym_name.len == strlen("fd_prestat_get") && + memcmp(sym_name.ptr, "fd_prestat_get", sym_name.len) == 0) { + imp->name = ImpName_fd_prestat_get; + } else if (sym_name.len == strlen("fd_pwrite") && + memcmp(sym_name.ptr, "fd_pwrite", sym_name.len) == 0) { + imp->name = ImpName_fd_pwrite; + } else if (sym_name.len == strlen("fd_read") && + memcmp(sym_name.ptr, "fd_read", sym_name.len) == 0) { + imp->name = ImpName_fd_read; + } else if (sym_name.len == strlen("fd_readdir") && + memcmp(sym_name.ptr, "fd_readdir", sym_name.len) == 0) { + imp->name = ImpName_fd_readdir; + } else if (sym_name.len == strlen("fd_write") && + memcmp(sym_name.ptr, "fd_write", sym_name.len) == 0) { + imp->name = ImpName_fd_write; + } else if (sym_name.len == strlen("path_create_directory") && + memcmp(sym_name.ptr, "path_create_directory", sym_name.len) == 0) { + imp->name = ImpName_path_create_directory; + } else if (sym_name.len == strlen("path_filestat_get") && + memcmp(sym_name.ptr, "path_filestat_get", sym_name.len) == 0) { + imp->name = ImpName_path_filestat_get; + } else if (sym_name.len == strlen("path_open") && + memcmp(sym_name.ptr, "path_open", sym_name.len) == 0) { + imp->name = ImpName_path_open; + } else if (sym_name.len == strlen("path_remove_directory") && + memcmp(sym_name.ptr, "path_remove_directory", sym_name.len) == 0) { + imp->name = ImpName_path_remove_directory; + } else if (sym_name.len == strlen("path_rename") && + memcmp(sym_name.ptr, "path_rename", sym_name.len) == 0) { + imp->name = ImpName_path_rename; + } else if (sym_name.len == strlen("path_unlink_file") && + memcmp(sym_name.ptr, "path_unlink_file", sym_name.len) == 0) { + imp->name = ImpName_path_unlink_file; + } else if (sym_name.len == strlen("proc_exit") && + memcmp(sym_name.ptr, "proc_exit", sym_name.len) == 0) { + imp->name = ImpName_proc_exit; + } else if (sym_name.len == strlen("random_get") && + memcmp(sym_name.ptr, "random_get", sym_name.len) == 0) { + imp->name = ImpName_random_get; + } else panic("unknown import name"); + + uint32_t desc = read32_uleb128(mod.ptr, &i); + if (desc != 0) panic("external kind not function"); + imp->type_idx = read32_uleb128(mod.ptr, &i); + } + } + + // Find _start in the exports + uint32_t start_fn_idx; + { + i = section_starts[Section_export]; + uint32_t count = read32_uleb128(mod.ptr, &i); + for (; count > 0; count -= 1) { + struct ByteSlice name = read_name(mod.ptr, &i); + uint32_t desc = read32_uleb128(mod.ptr, &i); + start_fn_idx = read32_uleb128(mod.ptr, &i); + if (desc == 0 && name.len == strlen("_start") && + memcmp(name.ptr, "_start", name.len) == 0) + { + break; + } + } + if (count == 0) panic("_start symbol not found"); + } + + // Map function indexes to offsets into the module and type index. + struct Function *functions; + uint32_t functions_len; + { + i = section_starts[Section_function]; + functions_len = read32_uleb128(mod.ptr, &i); + functions = arena_alloc(sizeof(struct Function) * functions_len); + for (size_t func_i = 0; func_i < functions_len; func_i += 1) { + struct Function *func = &functions[func_i]; + func->type_idx = read32_uleb128(mod.ptr, &i); + } + } + + // Allocate and initialize globals. + uint64_t *globals; + { + i = section_starts[Section_global]; + uint32_t globals_len = read32_uleb128(mod.ptr, &i); + globals = arena_alloc(sizeof(uint64_t) * globals_len); + for (size_t glob_i = 0; glob_i < globals_len; glob_i += 1) { + uint64_t *global = &globals[glob_i]; + uint32_t content_type = read32_uleb128(mod.ptr, &i); + uint32_t mutability = read32_uleb128(mod.ptr, &i); + if (mutability != 1) panic("expected mutable global"); + if (content_type != 0x7f) panic("unexpected content type"); + uint8_t opcode = mod.ptr[i]; + i += 1; + if (opcode != WasmOp_i32_const) panic("expected i32_const op"); + uint32_t init = read32_ileb128(mod.ptr, &i); + *global = (uint32_t)init; + } + } + + // Allocate and initialize memory. + uint32_t memory_len; + { + i = section_starts[Section_memory]; + uint32_t memories_len = read32_uleb128(mod.ptr, &i); + if (memories_len != 1) panic("unexpected memory count"); + uint32_t flags = read32_uleb128(mod.ptr, &i); + (void)flags; + memory_len = read32_uleb128(mod.ptr, &i) * wasm_page_size; + + i = section_starts[Section_data]; + uint32_t datas_count = read32_uleb128(mod.ptr, &i); + for (; datas_count > 0; datas_count -= 1) { + uint32_t mode = read32_uleb128(mod.ptr, &i); + if (mode != 0) panic("expected mode 0"); + enum WasmOp opcode = mod.ptr[i]; + i += 1; + if (opcode != WasmOp_i32_const) panic("expected opcode i32_const"); + uint32_t offset = read32_uleb128(mod.ptr, &i); + enum WasmOp end = mod.ptr[i]; + if (end != WasmOp_end) panic("expected end opcode"); + i += 1; + uint32_t bytes_len = read32_uleb128(mod.ptr, &i); + memcpy(memory + offset, mod.ptr + i, bytes_len); + i += bytes_len; + } + } + + uint32_t *table = NULL; + { + i = section_starts[Section_table]; + uint32_t table_count = read32_uleb128(mod.ptr, &i); + if (table_count > 1) { + panic("expected only one table section"); + } else if (table_count == 1) { + uint32_t element_type = read32_uleb128(mod.ptr, &i); + (void)element_type; + uint32_t has_max = read32_uleb128(mod.ptr, &i); + if (has_max != 1) panic("expected has_max==1"); + uint32_t initial = read32_uleb128(mod.ptr, &i); + (void)initial; + uint32_t maximum = read32_uleb128(mod.ptr, &i); + + i = section_starts[Section_element]; + uint32_t element_section_count = read32_uleb128(mod.ptr, &i); + if (element_section_count != 1) panic("expected one element section"); + uint32_t flags = read32_uleb128(mod.ptr, &i); + (void)flags; + enum WasmOp opcode = mod.ptr[i]; + i += 1; + if (opcode != WasmOp_i32_const) panic("expected op i32_const"); + uint32_t offset = read32_uleb128(mod.ptr, &i); + enum WasmOp end = mod.ptr[i]; + if (end != WasmOp_end) panic("expected op end"); + i += 1; + uint32_t elem_count = read32_uleb128(mod.ptr, &i); + + table = arena_alloc(sizeof(uint32_t) * maximum); + memset(table, 0, maximum); + + for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { + table[elem_i + offset] = read32_uleb128(mod.ptr, &i); + } + } + } + + struct VirtualMachine vm; + vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), + vm.mod_ptr = mod.ptr; + vm.opcodes = arena_alloc(2000000); + vm.operands = arena_alloc(sizeof(uint32_t) * 2000000); + vm.stack_top = 0; + vm.functions = functions; + vm.types = types; + vm.globals = globals; + vm.memory = memory; + vm.memory_len = memory_len; + vm.imports = imports; + vm.imports_len = imports_len; + vm.args = argv + vm_argv_start; + vm.table = table; + + { + uint32_t code_i = section_starts[Section_code]; + uint32_t codes_len = read32_uleb128(mod.ptr, &code_i); + if (codes_len != functions_len) panic("code/function length mismatch"); + struct ProgramCounter pc; + pc.opcode = 0; + pc.operand = 0; + for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) { + struct Function *func = &functions[func_i]; + uint32_t size = read32_uleb128(mod.ptr, &code_i); + uint32_t code_begin = code_i; + + struct TypeInfo *type_info = &vm.types[func->type_idx]; + func->locals_count = 0; + func->local_types = arena_alloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); + func->local_types[0] = type_info->param_types; + + for (uint32_t local_sets_count = read32_uleb128(mod.ptr, &code_i); + local_sets_count > 0; local_sets_count -= 1) { + uint32_t set_count = read32_uleb128(mod.ptr, &code_i); + int64_t local_type = read64_ileb128(mod.ptr, &code_i); + + uint32_t i = type_info->param_count + func->locals_count; + func->locals_count += set_count; + if ((type_info->param_count + func->locals_count + 31) / 32 > (i + 31) / 32) + func->local_types = arena_realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); + for (; i < type_info->param_count + func->locals_count; i += 1) + switch (local_type) { + case -1: case -3: bs_unset(func->local_types, i); break; + case -2: case -4: bs_set(func->local_types, i); break; + default: panic("unexpected local type"); + } + } + + func->entry_pc = pc; + vm_decodeCode(&vm, func, &code_i, &pc); + if (code_i != code_begin + size) panic("bad code size"); + } + + uint64_t opcode_counts[0x100]; + memset(opcode_counts, 0, 0x100); + uint64_t prefixed_opcode_counts[0x100]; + memset(prefixed_opcode_counts, 0, 0x100); + bool is_prefixed = false; + for (uint32_t opcode_i = 0; opcode_i < pc.opcode; opcode_i += 1) { + uint8_t opcode = vm.opcodes[opcode_i]; + if (!is_prefixed) { + opcode_counts[opcode] += 1; + is_prefixed = opcode == WasmOp_prefixed; + } else { + prefixed_opcode_counts[opcode] += 1; + is_prefixed = false; + } + } + } + + vm_call(&vm, start_fn_idx); + vm_run(&vm); + + return 0; +} From 39fd77bc163f0d7fc7408cbb4e48f960b4739448 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 17:40:04 -0700 Subject: [PATCH 13/68] interpret the WASI blob to produce zig2.c and compiler_rt.c * synchronize zig1.c from zig-wasi external project * change the way argv works to avoid absolute paths * autodetect isatty * compiler_rt: disable some functions when object format is C * add missing flag from config.zig.in The next problem is that compiling compiler_rt.c with gcc gives "conflicting types" errors for `__eqhf2` and friends. --- CMakeLists.txt | 24 +- lib/compiler_rt.zig | 26 +- stage1/config.zig.in | 1 + stage1/zig1.c | 675 ++++++++++++++++++++++++++++++------------- 4 files changed, 491 insertions(+), 235 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9fd5614bcb3..d48187a90fec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -702,29 +702,24 @@ if(MSVC) set(ZIG2_COMPILE_FLAGS "/std:c99") set(ZIG2_LINK_FLAGS "/STACK:16777216") else() - #set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native") - set(ZIG1_COMPILE_FLAGS "-std=c99 -march=native") + set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native") set(ZIG2_COMPILE_FLAGS "-std=c99 -O2 -march=native") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() add_executable(zig1 ${STAGE1_SOURCES}) set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) -#target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/lib") target_link_libraries(zig1 LINK_PUBLIC m) set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") set(BUILD_ZIG2_ARGS "${CMAKE_SOURCE_DIR}/lib" - "${CMAKE_BINARY_DIR}/zig1-cache" + "${CMAKE_BINARY_DIR}" + zig2 "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" build-exe src/main.zig -ofmt=c -lc - --name zig2 - --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" - --pkg-end -target x86_64-linux-musl # TODO: autodetect in zig1.c - --color on # TODO: autodetect in zig1.c -OReleaseFast ) @@ -739,12 +734,11 @@ add_custom_command( set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") set(BUILD_COMPILER_RT_ARGS "${CMAKE_SOURCE_DIR}/lib" - "${CMAKE_BINARY_DIR}/zig1-cache" + "${CMAKE_BINARY_DIR}" + compiler_rt "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" build-obj lib/compiler_rt.zig -ofmt=c - --name compiler_rt -target x86_64-linux-musl # TODO: autodetect in zig1.c - --color on # TODO: autodetect in zig1.c -OReleaseFast ) @@ -757,13 +751,9 @@ add_custom_command( ) -add_executable(zig2 ${ZIG2_C_SOURCE}) +add_executable(zig2 ${ZIG2_C_SOURCE} ${ZIG_COMPILER_RT_C_SOURCE}) set_target_properties(zig2 PROPERTIES COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS} LINK_FLAGS ${ZIG2_LINK_FLAGS} ) - - - - - +target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib") diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 44146d04e930..3ffaf9f0e5dc 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -3,13 +3,6 @@ const builtin = @import("builtin"); pub const panic = @import("compiler_rt/common.zig").panic; comptime { - _ = @import("compiler_rt/atomics.zig"); - - // macOS has these functions inside libSystem. - if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { - _ = @import("compiler_rt/aarch64_outline_atomics.zig"); - } - _ = @import("compiler_rt/addf3.zig"); _ = @import("compiler_rt/addhf3.zig"); _ = @import("compiler_rt/addsf3.zig"); @@ -216,9 +209,18 @@ comptime { _ = @import("compiler_rt/aullrem.zig"); _ = @import("compiler_rt/clear_cache.zig"); - _ = @import("compiler_rt/memcpy.zig"); - _ = @import("compiler_rt/memset.zig"); - _ = @import("compiler_rt/memmove.zig"); - _ = @import("compiler_rt/memcmp.zig"); - _ = @import("compiler_rt/bcmp.zig"); + if (@import("builtin").object_format != .c) { + _ = @import("compiler_rt/atomics.zig"); + + // macOS has these functions inside libSystem. + if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { + _ = @import("compiler_rt/aarch64_outline_atomics.zig"); + } + + _ = @import("compiler_rt/memcpy.zig"); + _ = @import("compiler_rt/memset.zig"); + _ = @import("compiler_rt/memmove.zig"); + _ = @import("compiler_rt/memcmp.zig"); + _ = @import("compiler_rt/bcmp.zig"); + } } diff --git a/stage1/config.zig.in b/stage1/config.zig.in index 48d1f75adbcb..347c757f9385 100644 --- a/stage1/config.zig.in +++ b/stage1/config.zig.in @@ -11,3 +11,4 @@ pub const value_tracing = false; pub const have_stage1 = false; pub const skip_non_native = false; pub const only_c = true; +pub const force_gpa = false; diff --git a/stage1/zig1.c b/stage1/zig1.c index 1cdac5a52b93..34df5230f575 100755 --- a/stage1/zig1.c +++ b/stage1/zig1.c @@ -10,11 +10,16 @@ #include #include +#include #include #include -#include +#include #include +#ifdef __linux__ +#include +#endif + enum wasi_errno_t { WASI_ESUCCESS = 0, WASI_E2BIG = 1, @@ -131,15 +136,12 @@ static uint64_t rotr64(uint64_t n, unsigned c) { static void *arena_alloc(size_t n) { void *ptr = malloc(n); if (!ptr) panic("out of memory"); +#ifndef NDEBUG + memset(ptr, 0xaa, n); // to match the zig version +#endif return ptr; } -static void *arena_realloc(void *ptr, size_t new_n) { - void *new_ptr = realloc(ptr, new_n); - if (!new_ptr) panic("out of memory"); - return new_ptr; -} - static int err_wrap(const char *prefix, int rc) { if (rc == -1) { perror(prefix); @@ -152,7 +154,7 @@ static bool bs_isSet(const uint32_t *bitset, uint32_t index) { return (bitset[index >> 5] >> (index & 0x1f)) & 1; } static void bs_set(uint32_t *bitset, uint32_t index) { - bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f)); + bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f)); } static void bs_unset(uint32_t *bitset, uint32_t index) { bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f)); @@ -213,7 +215,7 @@ static const struct Preopen *find_preopen(int32_t wasi_fd) { return NULL; } -static const size_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB +static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB static uint16_t read_u16_le(const char *ptr) { const uint8_t *u8_ptr = (const uint8_t *)ptr; @@ -655,6 +657,7 @@ struct VirtualMachine { /// Points to one after the last stack item. uint32_t stack_top; struct ProgramCounter pc; + /// Actual memory usage of the WASI code. The capacity is max_memory. uint32_t memory_len; const char *mod_ptr; uint8_t *opcodes; @@ -666,7 +669,7 @@ struct VirtualMachine { char *memory; struct Import *imports; uint32_t imports_len; - char **args; + const char **args; uint32_t *table; }; @@ -678,22 +681,156 @@ static int to_host_fd(int32_t wasi_fd) { static enum wasi_errno_t to_wasi_err(int err) { switch (err) { + case E2BIG: return WASI_E2BIG; case EACCES: return WASI_EACCES; + case EADDRINUSE: return WASI_EADDRINUSE; + case EADDRNOTAVAIL: return WASI_EADDRNOTAVAIL; + case EAFNOSUPPORT: return WASI_EAFNOSUPPORT; + case EAGAIN: return WASI_EAGAIN; + case EALREADY: return WASI_EALREADY; + case EBADF: return WASI_EBADF; + case EBADMSG: return WASI_EBADMSG; + case EBUSY: return WASI_EBUSY; + case ECANCELED: return WASI_ECANCELED; + case ECHILD: return WASI_ECHILD; + case ECONNABORTED: return WASI_ECONNABORTED; + case ECONNREFUSED: return WASI_ECONNREFUSED; + case ECONNRESET: return WASI_ECONNRESET; + case EDEADLK: return WASI_EDEADLK; + case EDESTADDRREQ: return WASI_EDESTADDRREQ; + case EDOM: return WASI_EDOM; case EDQUOT: return WASI_EDQUOT; - case EIO: return WASI_EIO; + case EEXIST: return WASI_EEXIST; + case EFAULT: return WASI_EFAULT; case EFBIG: return WASI_EFBIG; + case EHOSTUNREACH: return WASI_EHOSTUNREACH; + case EIDRM: return WASI_EIDRM; + case EILSEQ: return WASI_EILSEQ; + case EINPROGRESS: return WASI_EINPROGRESS; + case EINTR: return WASI_EINTR; + case EINVAL: return WASI_EINVAL; + case EIO: return WASI_EIO; + case EISCONN: return WASI_EISCONN; + case EISDIR: return WASI_EISDIR; + case ELOOP: return WASI_ELOOP; + case EMFILE: return WASI_EMFILE; + case EMLINK: return WASI_EMLINK; + case EMSGSIZE: return WASI_EMSGSIZE; + case EMULTIHOP: return WASI_EMULTIHOP; + case ENAMETOOLONG: return WASI_ENAMETOOLONG; + case ENETDOWN: return WASI_ENETDOWN; + case ENETRESET: return WASI_ENETRESET; + case ENETUNREACH: return WASI_ENETUNREACH; + case ENFILE: return WASI_ENFILE; + case ENOBUFS: return WASI_ENOBUFS; + case ENODEV: return WASI_ENODEV; + case ENOENT: return WASI_ENOENT; + case ENOEXEC: return WASI_ENOEXEC; + case ENOLCK: return WASI_ENOLCK; + case ENOLINK: return WASI_ENOLINK; + case ENOMEM: return WASI_ENOMEM; + case ENOMSG: return WASI_ENOMSG; + case ENOPROTOOPT: return WASI_ENOPROTOOPT; case ENOSPC: return WASI_ENOSPC; + case ENOSYS: return WASI_ENOSYS; + case ENOTCONN: return WASI_ENOTCONN; + case ENOTDIR: return WASI_ENOTDIR; + case ENOTEMPTY: return WASI_ENOTEMPTY; + case ENOTRECOVERABLE: return WASI_ENOTRECOVERABLE; + case ENOTSOCK: return WASI_ENOTSOCK; + case EOPNOTSUPP: return WASI_EOPNOTSUPP; + case ENOTTY: return WASI_ENOTTY; + case ENXIO: return WASI_ENXIO; + case EOVERFLOW: return WASI_EOVERFLOW; + case EOWNERDEAD: return WASI_EOWNERDEAD; + case EPERM: return WASI_EPERM; case EPIPE: return WASI_EPIPE; - case EBADF: return WASI_EBADF; - case ENOMEM: return WASI_ENOMEM; - case ENOENT: return WASI_ENOENT; - case EEXIST: return WASI_EEXIST; + case EPROTO: return WASI_EPROTO; + case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT; + case EPROTOTYPE: return WASI_EPROTOTYPE; + case ERANGE: return WASI_ERANGE; + case EROFS: return WASI_EROFS; + case ESPIPE: return WASI_ESPIPE; + case ESRCH: return WASI_ESRCH; + case ESTALE: return WASI_ESTALE; + case ETIMEDOUT: return WASI_ETIMEDOUT; + case ETXTBSY: return WASI_ETXTBSY; + case EXDEV: return WASI_EXDEV; default: fprintf(stderr, "unexpected errno: %s\n", strerror(err)); abort(); }; } +enum wasi_filetype_t { + wasi_filetype_t_UNKNOWN, + wasi_filetype_t_BLOCK_DEVICE, + wasi_filetype_t_CHARACTER_DEVICE, + wasi_filetype_t_DIRECTORY, + wasi_filetype_t_REGULAR_FILE, + wasi_filetype_t_SOCKET_DGRAM, + wasi_filetype_t_SOCKET_STREAM, + wasi_filetype_t_SYMBOLIC_LINK, +}; + +static const uint16_t WASI_O_CREAT = 0x0001; +static const uint16_t WASI_O_DIRECTORY = 0x0002; +static const uint16_t WASI_O_EXCL = 0x0004; +static const uint16_t WASI_O_TRUNC = 0x0008; + +static const uint16_t WASI_FDFLAG_APPEND = 0x0001; +static const uint16_t WASI_FDFLAG_DSYNC = 0x0002; +static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004; +static const uint16_t WASI_FDFLAG_SYNC = 0x0010; + +static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull; +static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull; + +static enum wasi_filetype_t to_wasi_filetype(mode_t st_mode) { + switch (st_mode & S_IFMT) { + case S_IFBLK: + return wasi_filetype_t_BLOCK_DEVICE; + case S_IFCHR: + return wasi_filetype_t_CHARACTER_DEVICE; + case S_IFDIR: + return wasi_filetype_t_DIRECTORY; + case S_IFLNK: + return wasi_filetype_t_SYMBOLIC_LINK; + case S_IFREG: + return wasi_filetype_t_REGULAR_FILE; + default: + return wasi_filetype_t_UNKNOWN; + } +} + +static uint64_t to_wasi_timestamp(struct timespec ts) { + return ts.tv_sec * 1000000000ull + ts.tv_nsec; +} + +/// const filestat_t = extern struct { +/// dev: device_t, u64 +/// ino: inode_t, u64 +/// filetype: filetype_t, u8 +/// nlink: linkcount_t, u64 +/// size: filesize_t, u64 +/// atim: timestamp_t, u64 +/// mtim: timestamp_t, u64 +/// ctim: timestamp_t, u64 +/// }; +static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm, + uint32_t buf, struct stat st) +{ + write_u64_le(vm->memory + buf + 0x00, 0); // device + write_u64_le(vm->memory + buf + 0x08, st.st_ino); + write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode)); + write_u64_le(vm->memory + buf + 0x18, 1); // nlink + write_u64_le(vm->memory + buf + 0x20, st.st_size); + write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim)); + write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim)); + write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim)); + return WASI_ESUCCESS; +} + /// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, uint32_t argc, uint32_t argv_buf_size) @@ -713,17 +850,19 @@ static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, uint32_t argv, uint32_t argv_buf) { - panic("TODO implement wasi_args_get"); - //var argv_buf_i: usize = 0; - //for (vm->args) |arg, arg_i| { - // // Write the arg to the buffer. - // const argv_ptr = argv_buf + argv_buf_i; - // const arg_len = mem.span(arg).len + 1; - // mem.copy(u8, vm->memory[argv_buf + argv_buf_i ..], arg[0..arg_len]); - // argv_buf_i += arg_len; - - // write_u32_le(vm->memory[argv + 4 * arg_i ..][0..4], @intCast(u32, argv_ptr)); - //} + uint32_t argv_buf_i = 0; + uint32_t arg_i = 0; + for (;; arg_i += 1) { + const char *arg = vm->args[arg_i]; + if (!arg) break; + // Write the arg to the buffer. + uint32_t argv_ptr = argv_buf + argv_buf_i; + uint32_t arg_len = strlen(arg) + 1; + memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len); + argv_buf_i += arg_len; + + write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr); + } return WASI_ESUCCESS; } @@ -731,9 +870,15 @@ static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, uint32_t buf, uint32_t buf_len) { - panic("TODO implement wasi_random_get"); - //const host_buf = vm->memory[buf..][0..buf_len]; - //std.crypto.random.bytes(host_buf); +#ifdef __linux__ + if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) { + panic("getrandom failed"); + } +#else + for (uint32_t i = 0; i < buf_len; i += 1) { + vm->memory[buf + i] = rand(); + } +#endif return WASI_ESUCCESS; } @@ -745,10 +890,10 @@ static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { - panic("TODO implement wasi_fd_prestat_get"); - //const preopen = findPreopen(fd) orelse return .BADF; - //write_u32_le(vm->memory[buf + 0 ..][0..4], 0); - //write_u32_le(vm->memory[buf + 4 ..][0..4], @intCast(u32, preopen.name.len)); + const struct Preopen *preopen = find_preopen(fd); + if (!preopen) return WASI_EBADF; + write_u32_le(vm->memory + buf + 0, 0); + write_u32_le(vm->memory + buf + 4, preopen->name_len); return WASI_ESUCCESS; } @@ -756,19 +901,18 @@ static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm, int32_t fd, uint32_t path, uint32_t path_len) { - panic("TODO implement wasi_fd_prestat_dir_name"); - //const preopen = findPreopen(fd) orelse return .BADF; - //assert(path_len == preopen.name.len); - //mem.copy(u8, vm->memory[path..], preopen.name); + const struct Preopen *preopen = find_preopen(fd); + if (!preopen) return WASI_EBADF; + if (path_len != preopen->name_len) + panic("wasi_fd_prestat_dir_name expects correct name_len"); + memcpy(vm->memory + path, preopen->name, path_len); return WASI_ESUCCESS; } /// extern fn fd_close(fd: fd_t) errno_t; static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) { - panic("TODO implement wasi_fd_close"); - //_ = vm; - //const host_fd = toHostFd(fd); - //os.close(host_fd); + int host_fd = to_host_fd(fd); + close(host_fd); return WASI_ESUCCESS; } @@ -779,20 +923,18 @@ static enum wasi_errno_t wasi_fd_read( uint32_t iovs_len, // usize uint32_t nread // *usize ) { - panic("TODO implement wasi_fd_read"); - //const host_fd = toHostFd(fd); - //var i: u32 = 0; - //var total_read: usize = 0; - //while (i < iovs_len) : (i += 1) { - // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); - // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); - // const buf = vm->memory[ptr..][0..len]; - // const read = os.read(host_fd, buf) catch |err| return toWasiError(err); - // trace_log.debug("read {d} bytes out of {d}", .{ read, buf.len }); - // total_read += read; - // if (read != buf.len) break; - //} - //write_u32_le(vm->memory[nread..][0..4], @intCast(u32, total_read)); + int host_fd = to_host_fd(fd); + uint32_t i = 0; + size_t total_read = 0; + for (; i < iovs_len; i += 1) { + uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); + uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); + ssize_t amt_read = read(host_fd, vm->memory + ptr, len); + if (amt_read < 0) return to_wasi_err(errno); + total_read += amt_read; + if (amt_read != len) break; + } + write_u32_le(vm->memory + nread, total_read); return WASI_ESUCCESS; } @@ -826,19 +968,18 @@ static enum wasi_errno_t wasi_fd_pwrite( uint64_t offset, // wasi.filesize_t, uint32_t written_ptr // *usize ) { - panic("TODO implement wasi_fd_pwrite"); - //const host_fd = toHostFd(fd); - //var i: u32 = 0; - //var written: usize = 0; - //while (i < iovs_len) : (i += 1) { - // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); - // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); - // const buf = vm->memory[ptr..][0..len]; - // const w = os.pwrite(host_fd, buf, offset + written) catch |err| return toWasiError(err); - // written += w; - // if (w != buf.len) break; - //} - //write_u32_le(vm->memory[written_ptr..][0..4], @intCast(u32, written)); + int host_fd = to_host_fd(fd); + uint32_t i = 0; + size_t written = 0; + for (; i < iovs_len; i += 1) { + uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); + uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); + ssize_t w = pwrite(host_fd, vm->memory + ptr, len, offset + written); + if (w < 0) return to_wasi_err(errno); + written += w; + if (w != len) break; + } + write_u32_le(vm->memory + written_ptr, written); return WASI_ESUCCESS; } @@ -865,29 +1006,34 @@ static enum wasi_errno_t wasi_path_open( uint16_t fs_flags, // wasi.fdflags_t, uint32_t fd ) { - panic("TODO implement wasi_path_open"); - //const sub_path = vm->memory[path..][0..path_len]; - //const host_fd = toHostFd(dirfd); - //var flags: u32 = @as(u32, if (oflags & wasi.O.CREAT != 0) os.O.CREAT else 0) | - // @as(u32, if (oflags & wasi.O.DIRECTORY != 0) os.O.DIRECTORY else 0) | - // @as(u32, if (oflags & wasi.O.EXCL != 0) os.O.EXCL else 0) | - // @as(u32, if (oflags & wasi.O.TRUNC != 0) os.O.TRUNC else 0) | - // @as(u32, if (fs_flags & wasi.FDFLAG.APPEND != 0) os.O.APPEND else 0) | - // @as(u32, if (fs_flags & wasi.FDFLAG.DSYNC != 0) os.O.DSYNC else 0) | - // @as(u32, if (fs_flags & wasi.FDFLAG.NONBLOCK != 0) os.O.NONBLOCK else 0) | - // @as(u32, if (fs_flags & wasi.FDFLAG.SYNC != 0) os.O.SYNC else 0); - //if ((fs_rights_base & wasi.RIGHT.FD_READ != 0) and - // (fs_rights_base & wasi.RIGHT.FD_WRITE != 0)) - //{ - // flags |= os.O.RDWR; - //} else if (fs_rights_base & wasi.RIGHT.FD_WRITE != 0) { - // flags |= os.O.WRONLY; - //} else if (fs_rights_base & wasi.RIGHT.FD_READ != 0) { - // flags |= os.O.RDONLY; // no-op because O_RDONLY is 0 - //} - //const mode = 0o644; - //const res_fd = os.openat(host_fd, sub_path, flags, mode) catch |err| return toWasiError(err); - //mem.writeIntLittle(i32, vm->memory[fd..][0..4], res_fd); + char sub_path[PATH_MAX]; + memcpy(sub_path, vm->memory + path, path_len); + sub_path[path_len] = 0; + + int host_fd = to_host_fd(dirfd); + uint32_t flags = + (((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) | + (((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) | + (((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) | + (((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) | + (((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) | + (((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) | + (((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) | + (((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0); + + if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) && + ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0)) + { + flags |= O_RDWR; + } else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) { + flags |= O_WRONLY; + } else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) { + flags |= O_RDONLY; // no-op because O_RDONLY is 0 + } + mode_t mode = 0644; + int res_fd = openat(host_fd, sub_path, flags, mode); + if (res_fd == -1) return to_wasi_err(errno); + write_u32_le(vm->memory + fd, res_fd); return WASI_ESUCCESS; } @@ -899,23 +1045,26 @@ static enum wasi_errno_t wasi_path_filestat_get( uint32_t path_len, // usize uint32_t buf // *filestat_t ) { - panic("TODO implement wasi_path_filestat_get"); - //const sub_path = vm->memory[path..][0..path_len]; - //const host_fd = toHostFd(fd); - //const dir: fs.Dir = .{ .fd = host_fd }; - //const stat = dir.statFile(sub_path) catch |err| return toWasiError(err); - //return finishWasiStat(vm, buf, stat); - return WASI_ESUCCESS; + char sub_path[PATH_MAX]; + memcpy(sub_path, vm->memory + path, path_len); + sub_path[path_len] = 0; + + int host_fd = to_host_fd(fd); + struct stat st; + if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno); + return finish_wasi_stat(vm, buf, st); } /// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; -static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, int32_t fd, uint32_t path, uint32_t path_len) { - panic("TODO implement wasi_path_create_directory"); - //const sub_path = vm->memory[path..][0..path_len]; - //trace_log.debug("wasi_path_create_directory fd={d} path={s}", .{ fd, sub_path }); - //const host_fd = toHostFd(fd); - //const dir: fs.Dir = .{ .fd = host_fd }; - //dir.makeDir(sub_path) catch |err| return toWasiError(err); +static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, + int32_t wasi_fd, uint32_t path, uint32_t path_len) +{ + char sub_path[PATH_MAX]; + memcpy(sub_path, vm->memory + path, path_len); + sub_path[path_len] = 0; + + int host_fd = to_host_fd(wasi_fd); + if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno); return WASI_ESUCCESS; } @@ -928,35 +1077,33 @@ static enum wasi_errno_t wasi_path_rename( uint32_t new_path_ptr, // [*]const u8 uint32_t new_path_len // usize ) { - panic("TODO implement wasi_path_rename"); - //const old_path = vm->memory[old_path_ptr..][0..old_path_len]; - //const new_path = vm->memory[new_path_ptr..][0..new_path_len]; - //trace_log.debug("wasi_path_rename old_fd={d} old_path={s} new_fd={d} new_path={s}", .{ - // old_fd, old_path, new_fd, new_path, - //}); - //const old_host_fd = toHostFd(old_fd); - //const new_host_fd = toHostFd(new_fd); - //os.renameat(old_host_fd, old_path, new_host_fd, new_path) catch |err| return toWasiError(err); + char old_path[PATH_MAX]; + memcpy(old_path, vm->memory + old_path_ptr, old_path_len); + old_path[old_path_len] = 0; + + char new_path[PATH_MAX]; + memcpy(new_path, vm->memory + new_path_ptr, new_path_len); + new_path[new_path_len] = 0; + + int old_host_fd = to_host_fd(old_fd); + int new_host_fd = to_host_fd(new_fd); + if (renameat(old_host_fd, old_path, new_host_fd, new_path) == -1) return to_wasi_err(errno); return WASI_ESUCCESS; } /// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { - panic("TODO implement wasi_fd_filestat_get"); - //const host_fd = toHostFd(fd); - //const file = fs.File{ .handle = host_fd }; - //const stat = file.stat() catch |err| return toWasiError(err); - //return finishWasiStat(vm, buf, stat); - return WASI_ESUCCESS; + int host_fd = to_host_fd(fd); + struct stat st; + if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); + return finish_wasi_stat(vm, buf, st); } static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, int32_t fd, uint64_t size) { - panic("TODO implement wasi_fd_filestat_set_size"); - //_ = vm; - //const host_fd = toHostFd(fd); - //os.ftruncate(host_fd, size) catch |err| return toWasiError(err); + int host_fd = to_host_fd(fd); + if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno); return WASI_ESUCCESS; } @@ -968,14 +1115,13 @@ static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, /// fs_rights_inheriting: rights_t, u64 /// }; static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { - panic("TODO implement wasi_fd_fdstat_get"); - //const host_fd = toHostFd(fd); - //const file = fs.File{ .handle = host_fd }; - //const stat = file.stat() catch |err| return toWasiError(err); - //mem.writeIntLittle(u16, vm->memory[buf + 0x00 ..][0..2], @enumToInt(toWasiFileType(stat.kind))); - //mem.writeIntLittle(u16, vm->memory[buf + 0x02 ..][0..2], 0); // flags - //mem.writeIntLittle(u64, vm->memory[buf + 0x08 ..][0..8], math.maxInt(u64)); // rights_base - //mem.writeIntLittle(u64, vm->memory[buf + 0x10 ..][0..8], math.maxInt(u64)); // rights_inheriting + int host_fd = to_host_fd(fd); + struct stat st; + if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); + write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode)); + write_u16_le(vm->memory + buf + 0x02, 0); // flags + write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base + write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting return WASI_ESUCCESS; } @@ -983,31 +1129,24 @@ static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t f static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, uint32_t clock_id, uint64_t precision, uint32_t timestamp) { - panic("TODO implement wasi_clock_time_get"); - ////const host_clock_id = toHostClockId(clock_id); - //_ = precision; - //_ = clock_id; - //const wasi_ts = toWasiTimestamp(std.time.nanoTimestamp()); - //mem.writeIntLittle(u64, vm->memory[timestamp..][0..8], wasi_ts); + if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC"); + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno); + uint64_t wasi_ts = to_wasi_timestamp(ts); + write_u64_le(vm->memory + timestamp, wasi_ts); return WASI_ESUCCESS; } ///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { - panic("TODO implement wasi_debug"); - //const s = mem.sliceTo(vm->memory[text..], 0); - //trace_log.debug("wasi_debug: '{s}' number={d} {x}", .{ s, n, n }); + fprintf(stderr, "wasi_debug: '%s' number=%lu %lx\n", vm->memory + text, n, n); } /// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { - panic("TODO implement wasi_debug_slice"); - //const s = vm->memory[ptr..][0..len]; - //trace_log.debug("wasi_debug_slice: '{s}'", .{s}); + fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr); } - - struct Label { enum WasmOp opcode; uint32_t stack_depth; @@ -1049,6 +1188,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint static uint32_t stack_types[1 << (12 - 3)]; static struct Label labels[1 << 9]; +#ifndef NDEBUG + memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version +#endif uint32_t label_i = 0; labels[label_i].opcode = WasmOp_block; labels[label_i].stack_depth = stack_depth; @@ -1061,6 +1203,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint enum WasmPrefixedOp prefixed_opcode; if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i); + //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand); + //struct ProgramCounter old_pc = *pc; + uint32_t initial_stack_depth = stack_depth; if (unreachable_depth == 0) { switch (opcode) { @@ -1549,11 +1694,16 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint label->type_info.param_count = 0; label->type_info.param_types = 0; label->type_info.result_count = block_type != -0x40; - label->type_info.result_types = 0; switch (block_type) { - case -0x40: break; - case -1: case -3: bs_unset(&label->type_info.param_types, 0); break; - case -2: case -4: bs_set(&label->type_info.param_types, 0); break; + case -0x40: + case -1: + case -3: + label->type_info.result_types = 0; + break; + case -2: + case -4: + label->type_info.result_types = UINT32_MAX; + break; default: panic("unexpected param type"); } } else { @@ -1584,7 +1734,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case WasmOp_else: - { + if (unreachable_depth <= 1) { struct Label *label = &labels[label_i]; assert(label->opcode == WasmOp_if); label->opcode = WasmOp_else; @@ -1596,9 +1746,12 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case 1: - switch ((int)Label_operandType(label, 0)) { - case false: opcodes[pc->opcode] = Op_br_32; break; - case true: opcodes[pc->opcode] = Op_br_64; break; + //fprintf(stderr, "label_i=%u operand_type=%d\n", + // label_i, Label_operandType(label, 0)); + if (Label_operandType(label, 0)) { + opcodes[pc->opcode] = Op_br_64; + } else { + opcodes[pc->opcode] = Op_br_32; } break; @@ -1614,7 +1767,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint operands[label->extra.else_ref + 0] = pc->opcode; operands[label->extra.else_ref + 1] = pc->operand; stack_depth = label->stack_depth + label->type_info.param_count; - }; + } break; case WasmOp_end: @@ -1705,7 +1858,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint } break; - default: panic("unexpected opcode"); + default: panic("unreachable"); } pc->opcode += 1; operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; @@ -1748,11 +1901,6 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint label->ref_list = pc->operand + 1; pc->operand += 3; } - - opcodes[pc->opcode] = opcode; - pc->opcode += 1; - operands[pc->operand] = labels_len; - pc->operand += 1; } break; @@ -1796,7 +1944,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case WasmOp_return: - { + if (unreachable_depth <= 1) { uint32_t operand_count = Label_operandCount(&labels[0]); switch (operand_count) { case 0: @@ -2066,9 +2214,11 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; default: - opcodes[pc->opcode + 0] = Op_wasm; - opcodes[pc->opcode + 1] = opcode; - pc->opcode += 2; + if (unreachable_depth == 0) { + opcodes[pc->opcode + 0] = Op_wasm; + opcodes[pc->opcode + 1] = opcode; + pc->opcode += 2; + } break; case WasmOp_prefixed: @@ -2125,6 +2275,13 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint default: break; } + + //for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) { + // fprintf(stderr, "decoded opcode[%u] = %u\n", i, opcodes[i]); + //} + //for (uint32_t i = old_pc.operand; i < pc->operand; i += 1) { + // fprintf(stderr, "decoded operand[%u] = %u\n", i, operands[i]); + //} } } @@ -2184,7 +2341,7 @@ static float vm_pop_f32(struct VirtualMachine *vm) { } static double vm_pop_f64(struct VirtualMachine *vm) { - uint32_t integer = vm_pop_u64(vm); + uint64_t integer = vm_pop_u64(vm); double result; memcpy(&result, &integer, 8); return result; @@ -2251,7 +2408,7 @@ static void vm_callImport(struct VirtualMachine *vm, struct Import import) { break; case ImpName_fd_readdir: { - panic("TODO implement fd_readdir"); + panic("unexpected call to fd_readdir"); } break; case ImpName_fd_write: @@ -2422,8 +2579,12 @@ static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) { uint32_t fn_idx = fn_id - vm->imports_len; struct Function *func = &vm->functions[fn_idx]; + //struct TypeInfo *type_info = &vm->types[func->type_idx]; + //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_count: %u\n", + // fn_id, type_info->param_count, type_info->result_count, func->locals_count); + // Push zeroed locals to stack - memset(&vm->stack[vm->stack_top], 0, func->locals_count * sizeof(uint64_t)); + memset(vm->stack + vm->stack_top, 0, func->locals_count * sizeof(uint64_t)); vm->stack_top += func->locals_count; vm_push_u32(vm, vm->pc.opcode); @@ -2504,6 +2665,10 @@ static void vm_run(struct VirtualMachine *vm) { for (;;) { enum Op op = opcodes[pc->opcode]; pc->opcode += 1; + //if (vm->stack_top > 0) { + // fprintf(stderr, "stack[%u]=%lx pc=%u:%u, op=%u\n", + // vm->stack_top - 1, vm->stack[vm->stack_top - 1], pc->opcode, pc->operand, op); + //} switch (op) { case Op_unreachable: panic("unreachable reached"); @@ -2738,6 +2903,7 @@ static void vm_run(struct VirtualMachine *vm) { case Op_wasm: { enum WasmOp wasm_op = opcodes[pc->opcode]; + //fprintf(stderr, "op2=%x\n", wasm_op); pc->opcode += 1; switch (wasm_op) { case WasmOp_unreachable: @@ -2820,7 +2986,7 @@ static void vm_run(struct VirtualMachine *vm) { { uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); pc->operand += 1; - vm_push_u32(vm, vm->memory[offset]); + vm_push_u32(vm, (uint8_t)vm->memory[offset]); } break; case WasmOp_i32_load16_s: @@ -2850,7 +3016,7 @@ static void vm_run(struct VirtualMachine *vm) { { uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); pc->operand += 1; - vm_push_u64(vm, vm->memory[offset]); + vm_push_u64(vm, (uint8_t)vm->memory[offset]); } break; case WasmOp_i64_load16_s: @@ -2968,7 +3134,7 @@ static void vm_run(struct VirtualMachine *vm) { uint32_t page_count = vm_pop_u32(vm); uint32_t old_page_count = vm->memory_len / wasm_page_size; uint32_t new_len = vm->memory_len + page_count * wasm_page_size; - if (new_len > vm->memory_len) { + if (new_len > max_memory) { vm_push_i32(vm, -1); } else { vm->memory_len = new_len; @@ -3294,21 +3460,21 @@ static void vm_run(struct VirtualMachine *vm) { { uint32_t rhs = vm_pop_u32(vm); uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs << rhs); + vm_push_u32(vm, lhs << (rhs & 0x1f)); } break; case WasmOp_i32_shr_s: { uint32_t rhs = vm_pop_u32(vm); int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs >> rhs); + vm_push_i32(vm, lhs >> (rhs & 0x1f)); } break; case WasmOp_i32_shr_u: { uint32_t rhs = vm_pop_u32(vm); uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs >> rhs); + vm_push_u32(vm, lhs >> (rhs & 0x1f)); } break; case WasmOp_i32_rotl: @@ -3421,35 +3587,35 @@ static void vm_run(struct VirtualMachine *vm) { { uint64_t rhs = vm_pop_u64(vm); uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs << rhs); + vm_push_u64(vm, lhs << (rhs & 0x3f)); } break; case WasmOp_i64_shr_s: { uint64_t rhs = vm_pop_u64(vm); int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs >> rhs); + vm_push_i64(vm, lhs >> (rhs & 0x3f)); } break; case WasmOp_i64_shr_u: { uint64_t rhs = vm_pop_u64(vm); uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs >> rhs); + vm_push_u64(vm, lhs >> (rhs & 0x3f)); } break; case WasmOp_i64_rotl: { uint64_t rhs = vm_pop_u64(vm); uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotl64(lhs, rhs )); + vm_push_u64(vm, rotl64(lhs, rhs)); } break; case WasmOp_i64_rotr: { uint64_t rhs = vm_pop_u64(vm); uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotr64(lhs, rhs )); + vm_push_u64(vm, rotr64(lhs, rhs)); } break; @@ -3839,19 +4005,126 @@ static void vm_run(struct VirtualMachine *vm) { } } +static size_t common_prefix(const char *a, const char *b) { + size_t i = 0; + for (; a[i] == b[i]; i += 1) {} + return i; +} + int main(int argc, char **argv) { char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); const char *zig_lib_dir_path = argv[1]; - const char *zig_cache_dir_path = argv[2]; - const size_t vm_argv_start = 3; - const char *wasm_file = argv[vm_argv_start]; + const char *cmake_binary_dir_path = argv[2]; + const char *root_name = argv[3]; + size_t argv_i = 4; + const char *wasm_file = argv[argv_i]; + + size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path); + const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len; + size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path); + + const char *new_argv[30]; + char new_argv_buf[PATH_MAX + 1024]; + uint32_t new_argv_i = 0; + uint32_t new_argv_buf_i = 0; + + int cache_dir = -1; + { + char cache_dir_buf[PATH_MAX * 2]; + size_t i = 0; + size_t cmake_binary_dir_path_len = strlen(cmake_binary_dir_path); + + memcpy(cache_dir_buf + i, cmake_binary_dir_path, cmake_binary_dir_path_len); + i += cmake_binary_dir_path_len; + + cache_dir_buf[i] = '/'; + i += 1; + + memcpy(cache_dir_buf + i, "zig1-cache", strlen("zig1-cache")); + i += strlen("zig1-cache"); + + cache_dir_buf[i] = 0; + + mkdir(cache_dir_buf, 0777); + cache_dir = err_wrap("opening cache dir", + open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + } + + // Construct a new argv for the WASI code which has absolute paths + // converted to relative paths, and has the target and terminal status + // autodetected. + + // wasm file path + new_argv[new_argv_i] = argv[argv_i]; + new_argv_i += 1; + argv_i += 1; + + for(; argv[argv_i]; argv_i += 1) { + new_argv[new_argv_i] = argv[argv_i]; + new_argv_i += 1; + } + + { + new_argv[new_argv_i] = "--name"; + new_argv_i += 1; + + new_argv[new_argv_i] = root_name; + new_argv_i += 1; + + char *emit_bin_arg = new_argv_buf + new_argv_buf_i; + memcpy(new_argv_buf + new_argv_buf_i, "-femit-bin=", strlen("-femit-bin=")); + new_argv_buf_i += strlen("-femit-bin="); + memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len); + new_argv_buf_i += rel_cmake_bin_path_len; + new_argv_buf[new_argv_buf_i] = '/'; + new_argv_buf_i += 1; + memcpy(new_argv_buf + new_argv_buf_i, root_name, strlen(root_name)); + new_argv_buf_i += strlen(root_name); + memcpy(new_argv_buf + new_argv_buf_i, ".c", 3); + new_argv_buf_i += 3; + + new_argv[new_argv_i] = emit_bin_arg; + new_argv_i += 1; + } + + { + new_argv[new_argv_i] = "--pkg-begin"; + new_argv_i += 1; + + new_argv[new_argv_i] = "build_options"; + new_argv_i += 1; + + char *build_options_path = new_argv_buf + new_argv_buf_i; + memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len); + new_argv_buf_i += rel_cmake_bin_path_len; + new_argv_buf[new_argv_buf_i] = '/'; + new_argv_buf_i += 1; + memcpy(new_argv_buf + new_argv_buf_i, "config.zig", strlen("config.zig")); + new_argv_buf_i += strlen("config.zig"); + new_argv_buf[new_argv_buf_i] = 0; + new_argv_buf_i += 1; + + new_argv[new_argv_i] = build_options_path; + new_argv_i += 1; + + new_argv[new_argv_i] = "--pkg-end"; + new_argv_i += 1; + } + + if (isatty(STDERR_FILENO) != 0) { + new_argv[new_argv_i] = "--color"; + new_argv_i += 1; + + new_argv[new_argv_i] = "on"; + new_argv_i += 1; + } + + new_argv[new_argv_i] = NULL; const struct ByteSlice mod = read_file_alloc(wasm_file); int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); - mkdir(zig_cache_dir_path, 0666); - int cache_dir = err_wrap("opening cache dir", open(zig_cache_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); add_preopen(0, "stdin", STDIN_FILENO); @@ -3873,7 +4146,7 @@ int main(int argc, char **argv) { if (version != 1) panic("bad wasm version"); uint32_t section_starts[13]; - memset(§ion_starts, 0, 4 * 13); + memset(§ion_starts, 0, sizeof(uint32_t) * 13); while (i < mod.len) { uint8_t section_id = mod.ptr[i]; @@ -3895,6 +4168,7 @@ int main(int argc, char **argv) { i += 1; info->param_count = read32_uleb128(mod.ptr, &i); + if (info->param_count > 32) panic("found a type with over 32 parameters"); info->param_types = 0; for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { int64_t param_type = read64_ileb128(mod.ptr, &i); @@ -4133,7 +4407,7 @@ int main(int argc, char **argv) { uint32_t elem_count = read32_uleb128(mod.ptr, &i); table = arena_alloc(sizeof(uint32_t) * maximum); - memset(table, 0, maximum); + memset(table, 0, sizeof(uint32_t) * maximum); for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { table[elem_i + offset] = read32_uleb128(mod.ptr, &i); @@ -4142,6 +4416,9 @@ int main(int argc, char **argv) { } struct VirtualMachine vm; +#ifndef NDEBUG + memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version +#endif vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), vm.mod_ptr = mod.ptr; vm.opcodes = arena_alloc(2000000); @@ -4154,7 +4431,7 @@ int main(int argc, char **argv) { vm.memory_len = memory_len; vm.imports = imports; vm.imports_len = imports_len; - vm.args = argv + vm_argv_start; + vm.args = new_argv; vm.table = table; { @@ -4171,18 +4448,19 @@ int main(int argc, char **argv) { struct TypeInfo *type_info = &vm.types[func->type_idx]; func->locals_count = 0; - func->local_types = arena_alloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); + func->local_types = malloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); func->local_types[0] = type_info->param_types; for (uint32_t local_sets_count = read32_uleb128(mod.ptr, &code_i); - local_sets_count > 0; local_sets_count -= 1) { + local_sets_count > 0; local_sets_count -= 1) + { uint32_t set_count = read32_uleb128(mod.ptr, &code_i); int64_t local_type = read64_ileb128(mod.ptr, &code_i); uint32_t i = type_info->param_count + func->locals_count; func->locals_count += set_count; if ((type_info->param_count + func->locals_count + 31) / 32 > (i + 31) / 32) - func->local_types = arena_realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); + func->local_types = realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); for (; i < type_info->param_count + func->locals_count; i += 1) switch (local_type) { case -1: case -3: bs_unset(func->local_types, i); break; @@ -4191,26 +4469,11 @@ int main(int argc, char **argv) { } } + //fprintf(stderr, "set up func %u with pc %u:%u\n", func->type_idx, pc.opcode, pc.operand); func->entry_pc = pc; vm_decodeCode(&vm, func, &code_i, &pc); if (code_i != code_begin + size) panic("bad code size"); } - - uint64_t opcode_counts[0x100]; - memset(opcode_counts, 0, 0x100); - uint64_t prefixed_opcode_counts[0x100]; - memset(prefixed_opcode_counts, 0, 0x100); - bool is_prefixed = false; - for (uint32_t opcode_i = 0; opcode_i < pc.opcode; opcode_i += 1) { - uint8_t opcode = vm.opcodes[opcode_i]; - if (!is_prefixed) { - opcode_counts[opcode] += 1; - is_prefixed = opcode == WasmOp_prefixed; - } else { - prefixed_opcode_counts[opcode] += 1; - is_prefixed = false; - } - } } vm_call(&vm, start_fn_idx); From d1b3409df1804ff3182596ca41e2e2424c0918e7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 20:21:50 -0700 Subject: [PATCH 14/68] add zstd v1.5.2 only the decompression files --- stage1/zstd/LICENSE | 30 + stage1/zstd/lib/common/bitstream.h | 478 ++ stage1/zstd/lib/common/compiler.h | 335 + stage1/zstd/lib/common/cpu.h | 213 + stage1/zstd/lib/common/debug.c | 24 + stage1/zstd/lib/common/debug.h | 107 + stage1/zstd/lib/common/entropy_common.c | 368 ++ stage1/zstd/lib/common/error_private.c | 56 + stage1/zstd/lib/common/error_private.h | 159 + stage1/zstd/lib/common/fse.h | 717 +++ stage1/zstd/lib/common/fse_decompress.c | 403 ++ stage1/zstd/lib/common/huf.h | 364 ++ stage1/zstd/lib/common/mem.h | 442 ++ stage1/zstd/lib/common/pool.c | 355 + stage1/zstd/lib/common/pool.h | 84 + stage1/zstd/lib/common/portability_macros.h | 137 + stage1/zstd/lib/common/threading.c | 122 + stage1/zstd/lib/common/threading.h | 155 + stage1/zstd/lib/common/xxhash.c | 24 + stage1/zstd/lib/common/xxhash.h | 5686 +++++++++++++++++ stage1/zstd/lib/common/zstd_common.c | 83 + stage1/zstd/lib/common/zstd_deps.h | 111 + stage1/zstd/lib/common/zstd_internal.h | 493 ++ stage1/zstd/lib/common/zstd_trace.h | 163 + stage1/zstd/lib/decompress/huf_decompress.c | 1889 ++++++ .../lib/decompress/huf_decompress_amd64.S | 585 ++ stage1/zstd/lib/decompress/zstd_ddict.c | 244 + stage1/zstd/lib/decompress/zstd_ddict.h | 44 + stage1/zstd/lib/decompress/zstd_decompress.c | 2230 +++++++ .../lib/decompress/zstd_decompress_block.c | 2072 ++++++ .../lib/decompress/zstd_decompress_block.h | 68 + .../lib/decompress/zstd_decompress_internal.h | 236 + stage1/zstd/lib/zstd.h | 2575 ++++++++ stage1/zstd/lib/zstd_errors.h | 95 + 34 files changed, 21147 insertions(+) create mode 100644 stage1/zstd/LICENSE create mode 100644 stage1/zstd/lib/common/bitstream.h create mode 100644 stage1/zstd/lib/common/compiler.h create mode 100644 stage1/zstd/lib/common/cpu.h create mode 100644 stage1/zstd/lib/common/debug.c create mode 100644 stage1/zstd/lib/common/debug.h create mode 100644 stage1/zstd/lib/common/entropy_common.c create mode 100644 stage1/zstd/lib/common/error_private.c create mode 100644 stage1/zstd/lib/common/error_private.h create mode 100644 stage1/zstd/lib/common/fse.h create mode 100644 stage1/zstd/lib/common/fse_decompress.c create mode 100644 stage1/zstd/lib/common/huf.h create mode 100644 stage1/zstd/lib/common/mem.h create mode 100644 stage1/zstd/lib/common/pool.c create mode 100644 stage1/zstd/lib/common/pool.h create mode 100644 stage1/zstd/lib/common/portability_macros.h create mode 100644 stage1/zstd/lib/common/threading.c create mode 100644 stage1/zstd/lib/common/threading.h create mode 100644 stage1/zstd/lib/common/xxhash.c create mode 100644 stage1/zstd/lib/common/xxhash.h create mode 100644 stage1/zstd/lib/common/zstd_common.c create mode 100644 stage1/zstd/lib/common/zstd_deps.h create mode 100644 stage1/zstd/lib/common/zstd_internal.h create mode 100644 stage1/zstd/lib/common/zstd_trace.h create mode 100644 stage1/zstd/lib/decompress/huf_decompress.c create mode 100644 stage1/zstd/lib/decompress/huf_decompress_amd64.S create mode 100644 stage1/zstd/lib/decompress/zstd_ddict.c create mode 100644 stage1/zstd/lib/decompress/zstd_ddict.h create mode 100644 stage1/zstd/lib/decompress/zstd_decompress.c create mode 100644 stage1/zstd/lib/decompress/zstd_decompress_block.c create mode 100644 stage1/zstd/lib/decompress/zstd_decompress_block.h create mode 100644 stage1/zstd/lib/decompress/zstd_decompress_internal.h create mode 100644 stage1/zstd/lib/zstd.h create mode 100644 stage1/zstd/lib/zstd_errors.h diff --git a/stage1/zstd/LICENSE b/stage1/zstd/LICENSE new file mode 100644 index 000000000000..a793a8028925 --- /dev/null +++ b/stage1/zstd/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Zstandard software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/stage1/zstd/lib/common/bitstream.h b/stage1/zstd/lib/common/bitstream.h new file mode 100644 index 000000000000..84b6062ff350 --- /dev/null +++ b/stage1/zstd/lib/common/bitstream.h @@ -0,0 +1,478 @@ +/* ****************************************************************** + * bitstream + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ +#ifndef BITSTREAM_H_MODULE +#define BITSTREAM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif +/* +* This API consists of small unitary functions, which must be inlined for best performance. +* Since link-time-optimization is not available for all compilers, +* these functions are defined into a .h to be included. +*/ + +/*-**************************************** +* Dependencies +******************************************/ +#include "mem.h" /* unaligned access routines */ +#include "compiler.h" /* UNLIKELY() */ +#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ +#include "error_private.h" /* error codes and messages */ + + +/*========================================= +* Target specific +=========================================*/ +#ifndef ZSTD_NO_INTRINSICS +# if defined(__BMI__) && defined(__GNUC__) +# include /* support for bextr (experimental) */ +# elif defined(__ICCARM__) +# include +# endif +#endif + +#define STREAM_ACCUMULATOR_MIN_32 25 +#define STREAM_ACCUMULATOR_MIN_64 57 +#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) + + +/*-****************************************** +* bitStream encoding API (write forward) +********************************************/ +/* bitStream can mix input from multiple sources. + * A critical property of these streams is that they encode and decode in **reverse** direction. + * So the first bit sequence you add will be the last to be read, like a LIFO stack. + */ +typedef struct { + size_t bitContainer; + unsigned bitPos; + char* startPtr; + char* ptr; + char* endPtr; +} BIT_CStream_t; + +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity); +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); + +/* Start with initCStream, providing the size of buffer to write into. +* bitStream will never write outside of this buffer. +* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code. +* +* bits are first added to a local register. +* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. +* Writing data into memory is an explicit operation, performed by the flushBits function. +* Hence keep track how many bits are potentially stored into local register to avoid register overflow. +* After a flushBits, a maximum of 7 bits might still be stored into local register. +* +* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. +* +* Last operation is to close the bitStream. +* The function returns the final size of CStream in bytes. +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) +*/ + + +/*-******************************************** +* bitStream decoding API (read backward) +**********************************************/ +typedef struct { + size_t bitContainer; + unsigned bitsConsumed; + const char* ptr; + const char* start; + const char* limitPtr; +} BIT_DStream_t; + +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ + +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); + + +/* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream(). +*/ + + +/*-**************************************** +* unsafe API +******************************************/ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */ + +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); +/* unsafe version; does not check buffer overflow */ + +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); +/* faster, but works only if nbBits >= 1 */ + + + +/*-************************************************************** +* Internal functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ +# if STATIC_BMI2 == 1 + return _lzcnt_u32(val) ^ 31; +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; +# endif + } +} + +/*===== Local Constants =====*/ +static const unsigned BIT_mask[] = { + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, + 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, + 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ +#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) + +/*-************************************************************** +* bitStream encoding +****************************************************************/ +/*! BIT_initCStream() : + * `dstCapacity` must be > sizeof(size_t) + * @return : 0 if success, + * otherwise an error code (can be tested using ERR_isError()) */ +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + bitC->bitContainer = 0; + bitC->bitPos = 0; + bitC->startPtr = (char*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer); + if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall); + return 0; +} + +/*! BIT_addBits() : + * can add up to 31 bits into `bitC`. + * Note : does not check for register overflow ! */ +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); + assert(nbBits < BIT_MASK_SIZE); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_addBitsFast() : + * works only if `value` is _clean_, + * meaning all high bits above nbBits are 0 */ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + assert((value>>nbBits) == 0); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= value << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_flushBitsFast() : + * assumption : bitContainer has not overflowed + * unsafe version; does not check buffer overflow */ +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_flushBits() : + * assumption : bitContainer has not overflowed + * safe version; check for buffer overflow, and prevents it. + * note : does not signal buffer overflow. + * overflow will be revealed later on using BIT_closeCStream() */ +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_closeCStream() : + * @return : size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) +{ + BIT_addBitsFast(bitC, 1, 1); /* endMark */ + BIT_flushBits(bitC); + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); +} + + +/*-******************************************************** +* bitStream decoding +**********************************************************/ +/*! BIT_initDStream() : + * Initialize a BIT_DStream_t. + * `bitD` : a pointer to an already allocated BIT_DStream_t structure. + * `srcSize` must be the *exact* size of the bitStream, in bytes. + * @return : size of stream (== srcSize), or an errorCode if a problem is detected + */ +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) +{ + if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + + bitD->start = (const char*)srcBuffer; + bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); + + if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ + bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); + bitD->bitContainer = MEM_readLEST(bitD->ptr); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } + } else { + bitD->ptr = bitD->start; + bitD->bitContainer = *(const BYTE*)(bitD->start); + switch(srcSize) + { + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + ZSTD_FALLTHROUGH; + + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + ZSTD_FALLTHROUGH; + + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + ZSTD_FALLTHROUGH; + + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + ZSTD_FALLTHROUGH; + + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + ZSTD_FALLTHROUGH; + + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + ZSTD_FALLTHROUGH; + + default: break; + } + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ + } + bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; + } + + return srcSize; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +{ + return bitContainer >> start; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +{ + U32 const regMask = sizeof(bitContainer)*8 - 1; + /* if start > regMask, bitstream is corrupted, and result is undefined */ + assert(nbBits < BIT_MASK_SIZE); + /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better + * than accessing memory. When bmi2 instruction is not present, we consider + * such cpus old (pre-Haswell, 2013) and their performance is not of that + * importance. + */ +#if defined(__x86_64__) || defined(_M_X86) + return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); +#else + return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; +#endif +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ +#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 + return _bzhi_u64(bitContainer, nbBits); +#else + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +#endif +} + +/*! BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified. + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. + * @return : value extracted */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +{ + /* arbitrate between double-shift and shift+mask */ +#if 1 + /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8, + * bitstream is likely corrupted, and result is undefined */ + return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits); +#else + /* this code path is slower on my os-x laptop */ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask); +#endif +} + +/*! BIT_lookBitsFast() : + * unsafe version; only works if nbBits >= 1 */ +MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) +{ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + assert(nbBits >= 1); + return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); +} + +MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +{ + bitD->bitsConsumed += nbBits; +} + +/*! BIT_readBits() : + * Read (consume) next n bits from local register and update. + * Pay attention to not read more than nbBits contained into local register. + * @return : extracted value. */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBits(bitD, nbBits); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_readBitsFast() : + * unsafe version; only works only if nbBits >= 1 */ +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBitsFast(bitD, nbBits); + assert(nbBits >= 1); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_reloadDStreamFast() : + * Similar to BIT_reloadDStream(), but with two differences: + * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! + * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this + * point you must use BIT_reloadDStream() to reload. + */ +MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) +{ + if (UNLIKELY(bitD->ptr < bitD->limitPtr)) + return BIT_DStream_overflow; + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; +} + +/*! BIT_reloadDStream() : + * Refill `bitD` from buffer previously set in BIT_initDStream() . + * This function is safe, it guarantees it will not read beyond src buffer. + * @return : status of `BIT_DStream_t` internal register. + * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +{ + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ + return BIT_DStream_overflow; + + if (bitD->ptr >= bitD->limitPtr) { + return BIT_reloadDStreamFast(bitD); + } + if (bitD->ptr == bitD->start) { + if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; + return BIT_DStream_completed; + } + /* start < ptr < limitPtr */ + { U32 nbBytes = bitD->bitsConsumed >> 3; + BIT_DStream_status result = BIT_DStream_unfinished; + if (bitD->ptr - nbBytes < bitD->start) { + nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ + result = BIT_DStream_endOfBuffer; + } + bitD->ptr -= nbBytes; + bitD->bitsConsumed -= nbBytes*8; + bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */ + return result; + } +} + +/*! BIT_endOfDStream() : + * @return : 1 if DStream has _exactly_ reached its end (all bits consumed). + */ +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) +{ + return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* BITSTREAM_H_MODULE */ diff --git a/stage1/zstd/lib/common/compiler.h b/stage1/zstd/lib/common/compiler.h new file mode 100644 index 000000000000..516930c01ec9 --- /dev/null +++ b/stage1/zstd/lib/common/compiler.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMPILER_H +#define ZSTD_COMPILER_H + +#include "portability_macros.h" + +/*-******************************************************* +* Compiler specifics +*********************************************************/ +/* force inlining */ + +#if !defined(ZSTD_NO_INLINE) +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# define INLINE_KEYWORD inline +#else +# define INLINE_KEYWORD +#endif + +#if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_INLINE_ATTR __attribute__((always_inline)) +#elif defined(_MSC_VER) +# define FORCE_INLINE_ATTR __forceinline +#else +# define FORCE_INLINE_ATTR +#endif + +#else + +#define INLINE_KEYWORD +#define FORCE_INLINE_ATTR + +#endif + +/** + On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). + This explicitly marks such functions as __cdecl so that the code will still compile + if a CC other than __cdecl has been made the default. +*/ +#if defined(_MSC_VER) +# define WIN_CDECL __cdecl +#else +# define WIN_CDECL +#endif + +/** + * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant + * parameters. They must be inlined for the compiler to eliminate the constant + * branches. + */ +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +/** + * HINT_INLINE is used to help the compiler generate better code. It is *not* + * used for "templates", so it can be tweaked based on the compilers + * performance. + * + * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the + * always_inline attribute. + * + * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline + * attribute. + */ +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 +# define HINT_INLINE static INLINE_KEYWORD +#else +# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR +#endif + +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +#if defined(__GNUC__) +# define UNUSED_ATTR __attribute__((unused)) +#else +# define UNUSED_ATTR +#endif + +/* force no inlining */ +#ifdef _MSC_VER +# define FORCE_NOINLINE static __declspec(noinline) +#else +# if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_NOINLINE static __attribute__((__noinline__)) +# else +# define FORCE_NOINLINE static +# endif +#endif + + +/* target attribute */ +#if defined(__GNUC__) || defined(__ICCARM__) +# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) +#else +# define TARGET_ATTRIBUTE(target) +#endif + +/* Target attribute for BMI2 dynamic dispatch. + * Enable lzcnt, bmi, and bmi2. + * We test for bmi1 & bmi2. lzcnt is included in bmi1. + */ +#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") + +/* prefetch + * can be disabled, by declaring NO_PREFETCH build macro */ +#if defined(NO_PREFETCH) +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) +# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) +# else +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* NO_PREFETCH */ + +#define CACHELINE_SIZE 64 + +#define PREFETCH_AREA(p, s) { \ + const char* const _ptr = (const char*)(p); \ + size_t const _size = (size_t)(s); \ + size_t _pos; \ + for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ + PREFETCH_L2(_ptr + _pos); \ + } \ +} + +/* vectorization + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, + * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) +# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) +# else +# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")") +# endif +#else +# define DONT_VECTORIZE +#endif + +/* Tell the compiler that a branch is likely or unlikely. + * Only use these macros if it causes the compiler to generate better code. + * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc + * and clang, please do. + */ +#if defined(__GNUC__) +#define LIKELY(x) (__builtin_expect((x), 1)) +#define UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif + +/* disable warnings */ +#ifdef _MSC_VER /* Visual Studio */ +# include /* For Visual 2005 */ +# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ +# pragma warning(disable : 4324) /* disable: C4324: padded structure */ +#endif + +/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ +#ifndef STATIC_BMI2 +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) +# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 +# define STATIC_BMI2 1 +# endif +# endif +#endif + +#ifndef STATIC_BMI2 + #define STATIC_BMI2 0 +#endif + +/* compile time determination of SIMD support */ +#if !defined(ZSTD_NO_INTRINSICS) +# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +# define ZSTD_ARCH_X86_SSE2 +# endif +# if defined(__ARM_NEON) || defined(_M_ARM64) +# define ZSTD_ARCH_ARM_NEON +# endif +# +# if defined(ZSTD_ARCH_X86_SSE2) +# include +# elif defined(ZSTD_ARCH_ARM_NEON) +# include +# endif +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define ZSTD_HAS_C_ATTRIBUTE(x) 0 +#endif + +/* Only use C++ attributes in C++. Some compilers report support for C++ + * attributes when compiling with C. + */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. + * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough + * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * - Else: __attribute__((__fallthrough__)) + */ +#ifndef ZSTD_FALLTHROUGH +# if ZSTD_HAS_C_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif __has_attribute(__fallthrough__) +/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon + * gcc complains about: a label can only be part of a statement and a declaration is not a statement. + */ +# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__)) +# else +# define ZSTD_FALLTHROUGH +# endif +#endif + +/*-************************************************************** +* Alignment check +*****************************************************************/ + +/* this test was initially positioned in mem.h, + * but this file is removed (or replaced) for linux kernel + * so it's now hosted in compiler.h, + * which remains valid for both user & kernel spaces. + */ + +#ifndef ZSTD_ALIGNOF +# if defined(__GNUC__) || defined(_MSC_VER) +/* covers gcc, clang & MSVC */ +/* note : this section must come first, before C11, + * due to a limitation in the kernel source generator */ +# define ZSTD_ALIGNOF(T) __alignof(T) + +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +/* C11 support */ +# include +# define ZSTD_ALIGNOF(T) alignof(T) + +# else +/* No known support for alignof() - imperfect backup */ +# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) + +# endif +#endif /* ZSTD_ALIGNOF */ + +/*-************************************************************** +* Sanitizer +*****************************************************************/ + +#if ZSTD_MEMORY_SANITIZER +/* Not all platforms that support msan provide sanitizers/msan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ +#define ZSTD_DEPS_NEED_STDINT +#include "zstd_deps.h" /* intptr_t */ + +/* Make memory region fully initialized (without changing its contents). */ +void __msan_unpoison(const volatile void *a, size_t size); + +/* Make memory region fully uninitialized (without changing its contents). + This is a legacy interface that does not update origin information. Use + __msan_allocated_memory() instead. */ +void __msan_poison(const volatile void *a, size_t size); + +/* Returns the offset of the first (at least partially) poisoned byte in the + memory range, or -1 if the whole range is good. */ +intptr_t __msan_test_shadow(const volatile void *x, size_t size); +#endif + +#if ZSTD_ADDRESS_SANITIZER +/* Not all platforms that support asan provide sanitizers/asan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ + +/** + * Marks a memory region ([addr, addr+size)) as unaddressable. + * + * This memory must be previously allocated by your program. Instrumented + * code is forbidden from accessing addresses in this region until it is + * unpoisoned. This function is not guaranteed to poison the entire region - + * it could poison only a subregion of [addr, addr+size) due to ASan + * alignment restrictions. + * + * \note This function is not thread-safe because no two threads can poison or + * unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_poison_memory_region(void const volatile *addr, size_t size); + +/** + * Marks a memory region ([addr, addr+size)) as addressable. + * + * This memory must be previously allocated by your program. Accessing + * addresses in this region is allowed until this region is poisoned again. + * This function could unpoison a super-region of [addr, addr+size) due + * to ASan alignment restrictions. + * + * \note This function is not thread-safe because no two threads can + * poison or unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#endif + +#endif /* ZSTD_COMPILER_H */ diff --git a/stage1/zstd/lib/common/cpu.h b/stage1/zstd/lib/common/cpu.h new file mode 100644 index 000000000000..8acd33be3cd0 --- /dev/null +++ b/stage1/zstd/lib/common/cpu.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMMON_CPU_H +#define ZSTD_COMMON_CPU_H + +/** + * Implementation taken from folly/CpuId.h + * https://github.com/facebook/folly/blob/master/folly/CpuId.h + */ + +#include "mem.h" + +#ifdef _MSC_VER +#include +#endif + +typedef struct { + U32 f1c; + U32 f1d; + U32 f7b; + U32 f7c; +} ZSTD_cpuid_t; + +MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { + U32 f1c = 0; + U32 f1d = 0; + U32 f7b = 0; + U32 f7c = 0; +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + int reg[4]; + __cpuid((int*)reg, 0); + { + int const n = reg[0]; + if (n >= 1) { + __cpuid((int*)reg, 1); + f1c = (U32)reg[2]; + f1d = (U32)reg[3]; + } + if (n >= 7) { + __cpuidex((int*)reg, 7, 0); + f7b = (U32)reg[1]; + f7c = (U32)reg[2]; + } + } +#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) + /* The following block like the normal cpuid branch below, but gcc + * reserves ebx for use of its pic register so we must specially + * handle the save and restore to avoid clobbering the register + */ + U32 n; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(n) + : "a"(0) + : "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(f1a), "=c"(f1c), "=d"(f1d) + : "a"(1)); + } + if (n >= 7) { + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%eax\n\t" + "popl %%ebx" + : "=a"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) + U32 n; + __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); + } + if (n >= 7) { + U32 f7a; + __asm__("cpuid" + : "=a"(f7a), "=b"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#endif + { + ZSTD_cpuid_t cpuid; + cpuid.f1c = f1c; + cpuid.f1d = f1d; + cpuid.f7b = f7b; + cpuid.f7c = f7c; + return cpuid; + } +} + +#define X(name, r, bit) \ + MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ + return ((cpuid.r) & (1U << bit)) != 0; \ + } + +/* cpuid(1): Processor Info and Feature Bits. */ +#define C(name, bit) X(name, f1c, bit) + C(sse3, 0) + C(pclmuldq, 1) + C(dtes64, 2) + C(monitor, 3) + C(dscpl, 4) + C(vmx, 5) + C(smx, 6) + C(eist, 7) + C(tm2, 8) + C(ssse3, 9) + C(cnxtid, 10) + C(fma, 12) + C(cx16, 13) + C(xtpr, 14) + C(pdcm, 15) + C(pcid, 17) + C(dca, 18) + C(sse41, 19) + C(sse42, 20) + C(x2apic, 21) + C(movbe, 22) + C(popcnt, 23) + C(tscdeadline, 24) + C(aes, 25) + C(xsave, 26) + C(osxsave, 27) + C(avx, 28) + C(f16c, 29) + C(rdrand, 30) +#undef C +#define D(name, bit) X(name, f1d, bit) + D(fpu, 0) + D(vme, 1) + D(de, 2) + D(pse, 3) + D(tsc, 4) + D(msr, 5) + D(pae, 6) + D(mce, 7) + D(cx8, 8) + D(apic, 9) + D(sep, 11) + D(mtrr, 12) + D(pge, 13) + D(mca, 14) + D(cmov, 15) + D(pat, 16) + D(pse36, 17) + D(psn, 18) + D(clfsh, 19) + D(ds, 21) + D(acpi, 22) + D(mmx, 23) + D(fxsr, 24) + D(sse, 25) + D(sse2, 26) + D(ss, 27) + D(htt, 28) + D(tm, 29) + D(pbe, 31) +#undef D + +/* cpuid(7): Extended Features. */ +#define B(name, bit) X(name, f7b, bit) + B(bmi1, 3) + B(hle, 4) + B(avx2, 5) + B(smep, 7) + B(bmi2, 8) + B(erms, 9) + B(invpcid, 10) + B(rtm, 11) + B(mpx, 14) + B(avx512f, 16) + B(avx512dq, 17) + B(rdseed, 18) + B(adx, 19) + B(smap, 20) + B(avx512ifma, 21) + B(pcommit, 22) + B(clflushopt, 23) + B(clwb, 24) + B(avx512pf, 26) + B(avx512er, 27) + B(avx512cd, 28) + B(sha, 29) + B(avx512bw, 30) + B(avx512vl, 31) +#undef B +#define C(name, bit) X(name, f7c, bit) + C(prefetchwt1, 0) + C(avx512vbmi, 1) +#undef C + +#undef X + +#endif /* ZSTD_COMMON_CPU_H */ diff --git a/stage1/zstd/lib/common/debug.c b/stage1/zstd/lib/common/debug.c new file mode 100644 index 000000000000..bb863c9ea616 --- /dev/null +++ b/stage1/zstd/lib/common/debug.c @@ -0,0 +1,24 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * This module only hosts one global variable + * which can be used to dynamically influence the verbosity of traces, + * such as DEBUGLOG and RAWLOG + */ + +#include "debug.h" + +int g_debuglevel = DEBUGLEVEL; diff --git a/stage1/zstd/lib/common/debug.h b/stage1/zstd/lib/common/debug.h new file mode 100644 index 000000000000..3b2a320a188d --- /dev/null +++ b/stage1/zstd/lib/common/debug.h @@ -0,0 +1,107 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * The purpose of this header is to enable debug functions. + * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, + * and DEBUG_STATIC_ASSERT() for compile-time. + * + * By default, DEBUGLEVEL==0, which means run-time debug is disabled. + * + * Level 1 enables assert() only. + * Starting level 2, traces can be generated and pushed to stderr. + * The higher the level, the more verbose the traces. + * + * It's possible to dynamically adjust level using variable g_debug_level, + * which is only declared if DEBUGLEVEL>=2, + * and is a global variable, not multi-thread protected (use with care) + */ + +#ifndef DEBUG_H_12987983217 +#define DEBUG_H_12987983217 + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* static assert is triggered at compile time, leaving no runtime artefact. + * static assert only works with compile-time constants. + * Also, this variant can only be used inside a function. */ +#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) + + +/* DEBUGLEVEL is expected to be defined externally, + * typically through compiler command line. + * Value must be a number. */ +#ifndef DEBUGLEVEL +# define DEBUGLEVEL 0 +#endif + + +/* recommended values for DEBUGLEVEL : + * 0 : release mode, no debug, all run-time checks disabled + * 1 : enables assert() only, no display + * 2 : reserved, for currently active debug path + * 3 : events once per object lifetime (CCtx, CDict, etc.) + * 4 : events once per frame + * 5 : events once per block + * 6 : events once per sequence (verbose) + * 7+: events at every position (*very* verbose) + * + * It's generally inconvenient to output traces > 5. + * In which case, it's possible to selectively trigger high verbosity levels + * by modifying g_debug_level. + */ + +#if (DEBUGLEVEL>=1) +# define ZSTD_DEPS_NEED_ASSERT +# include "zstd_deps.h" +#else +# ifndef assert /* assert may be already defined, due to prior #include */ +# define assert(condition) ((void)0) /* disable assert (default) */ +# endif +#endif + +#if (DEBUGLEVEL>=2) +# define ZSTD_DEPS_NEED_IO +# include "zstd_deps.h" +extern int g_debuglevel; /* the variable is only declared, + it actually lives in debug.c, + and is shared by the whole process. + It's not thread-safe. + It's useful when enabling very verbose levels + on selective conditions (such as position in src) */ + +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__VA_ARGS__); \ + } } +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ + ZSTD_DEBUG_PRINT(" \n"); \ + } } +#else +# define RAWLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + + +#if defined (__cplusplus) +} +#endif + +#endif /* DEBUG_H_12987983217 */ diff --git a/stage1/zstd/lib/common/entropy_common.c b/stage1/zstd/lib/common/entropy_common.c new file mode 100644 index 000000000000..4229b40c5eed --- /dev/null +++ b/stage1/zstd/lib/common/entropy_common.c @@ -0,0 +1,368 @@ +/* ****************************************************************** + * Common functions of New Generation Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************* +* Dependencies +***************************************/ +#include "mem.h" +#include "error_private.h" /* ERR_*, ERROR */ +#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ +#include "fse.h" +#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */ +#include "huf.h" + + +/*=== Version ===*/ +unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; } + + +/*=== Error Management ===*/ +unsigned FSE_isError(size_t code) { return ERR_isError(code); } +const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); } + +unsigned HUF_isError(size_t code) { return ERR_isError(code); } +const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } + + +/*-************************************************************** +* FSE NCount encoding-decoding +****************************************************************/ +static U32 FSE_ctz(U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + if (val != 0) { + unsigned long r; + _BitScanForward(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_ctz(val); +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return __CTZ(val); +# else /* Software version */ + U32 count = 0; + while ((val & 1) == 0) { + val >>= 1; + ++count; + } + return count; +# endif + } +} + +FORCE_INLINE_TEMPLATE +size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + const BYTE* const istart = (const BYTE*) headerBuffer; + const BYTE* const iend = istart + hbSize; + const BYTE* ip = istart; + int nbBits; + int remaining; + int threshold; + U32 bitStream; + int bitCount; + unsigned charnum = 0; + unsigned const maxSV1 = *maxSVPtr + 1; + int previous0 = 0; + + if (hbSize < 8) { + /* This function only works when hbSize >= 8 */ + char buffer[8] = {0}; + ZSTD_memcpy(buffer, headerBuffer, hbSize); + { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, + buffer, sizeof(buffer)); + if (FSE_isError(countSize)) return countSize; + if (countSize > hbSize) return ERROR(corruption_detected); + return countSize; + } } + assert(hbSize >= 8); + + /* init */ + ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + bitStream = MEM_readLE32(ip); + nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ + if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); + bitStream >>= 4; + bitCount = 4; + *tableLogPtr = nbBits; + remaining = (1<> 1; + while (repeats >= 12) { + charnum += 3 * 12; + if (LIKELY(ip <= iend-7)) { + ip += 3; + } else { + bitCount -= (int)(8 * (iend - 7 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + repeats = FSE_ctz(~bitStream | 0x80000000) >> 1; + } + charnum += 3 * repeats; + bitStream >>= 2 * repeats; + bitCount += 2 * repeats; + + /* Add the final repeat which isn't 0b11. */ + assert((bitStream & 3) < 3); + charnum += bitStream & 3; + bitCount += 2; + + /* This is an error, but break and return an error + * at the end, because returning out of a loop makes + * it harder for the compiler to optimize. + */ + if (charnum >= maxSV1) break; + + /* We don't need to set the normalized count to 0 + * because we already memset the whole buffer to 0. + */ + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + assert((bitCount >> 3) <= 3); /* For first condition to work */ + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } + { + int const max = (2*threshold-1) - remaining; + int count; + + if ((bitStream & (threshold-1)) < (U32)max) { + count = bitStream & (threshold-1); + bitCount += nbBits-1; + } else { + count = bitStream & (2*threshold-1); + if (count >= threshold) count -= max; + bitCount += nbBits; + } + + count--; /* extra accuracy */ + /* When it matters (small blocks), this is a + * predictable branch, because we don't use -1. + */ + if (count >= 0) { + remaining -= count; + } else { + assert(count == -1); + remaining += count; + } + normalizedCounter[charnum++] = (short)count; + previous0 = !count; + + assert(threshold > 1); + if (remaining < threshold) { + /* This branch can be folded into the + * threshold update condition because we + * know that threshold > 1. + */ + if (remaining <= 1) break; + nbBits = BIT_highbit32(remaining) + 1; + threshold = 1 << (nbBits - 1); + } + if (charnum >= maxSV1) break; + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } } + if (remaining != 1) return ERROR(corruption_detected); + /* Only possible when there are too many zeros. */ + if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); + if (bitCount > 32) return ERROR(corruption_detected); + *maxSVPtr = charnum-1; + + ip += (bitCount+7)>>3; + return ip-istart; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_readNCount_body_default( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} +#endif + +size_t FSE_readNCount_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); + } +#endif + (void)bmi2; + return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +size_t FSE_readNCount( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); +} + + +/*! HUF_readStats() : + Read compact Huffman tree, saved by HUF_writeCTable(). + `huffWeight` is destination buffer. + `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32. + @return : size read from `src` , or an error Code . + Note : Needed by HUF_readCTable() and HUF_readDTableX?() . +*/ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize) +{ + U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ + U32 weightTotal; + const BYTE* ip = (const BYTE*) src; + size_t iSize; + size_t oSize; + + if (!srcSize) return ERROR(srcSize_wrong); + iSize = ip[0]; + /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + + if (iSize >= 128) { /* special header */ + oSize = iSize - 127; + iSize = ((oSize+1)/2); + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + if (oSize >= hwSize) return ERROR(corruption_detected); + ip += 1; + { U32 n; + for (n=0; n> 4; + huffWeight[n+1] = ip[n/2] & 15; + } } } + else { /* header compressed with FSE (normal case) */ + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + /* max (hwSize-1) values decoded, as last one is implied */ + oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); + if (FSE_isError(oSize)) return oSize; + } + + /* collect weight stats */ + ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + weightTotal = 0; + { U32 n; for (n=0; n HUF_TABLELOG_MAX) return ERROR(corruption_detected); + rankStats[huffWeight[n]]++; + weightTotal += (1 << huffWeight[n]) >> 1; + } } + if (weightTotal == 0) return ERROR(corruption_detected); + + /* get last non-null symbol weight (implied, total must be 2^n) */ + { U32 const tableLog = BIT_highbit32(weightTotal) + 1; + if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); + *tableLogPtr = tableLog; + /* determine last weight */ + { U32 const total = 1 << tableLog; + U32 const rest = total - weightTotal; + U32 const verif = 1 << BIT_highbit32(rest); + U32 const lastWeight = BIT_highbit32(rest) + 1; + if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ + huffWeight[oSize] = (BYTE)lastWeight; + rankStats[lastWeight]++; + } } + + /* check tree construction validity */ + if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ + + /* results */ + *nbSymbolsPtr = (U32)(oSize+1); + return iSize+1; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); +} +#endif + +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); + } +#endif + (void)bmi2; + return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); +} diff --git a/stage1/zstd/lib/common/error_private.c b/stage1/zstd/lib/common/error_private.c new file mode 100644 index 000000000000..6d1135f8c373 --- /dev/null +++ b/stage1/zstd/lib/common/error_private.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* The purpose of this file is to have a single list of error strings embedded in binary */ + +#include "error_private.h" + +const char* ERR_getErrorString(ERR_enum code) +{ +#ifdef ZSTD_STRIP_ERROR_STRINGS + (void)code; + return "Error strings stripped"; +#else + static const char* const notErrorCode = "Unspecified error code"; + switch( code ) + { + case PREFIX(no_error): return "No error detected"; + case PREFIX(GENERIC): return "Error (generic)"; + case PREFIX(prefix_unknown): return "Unknown frame descriptor"; + case PREFIX(version_unsupported): return "Version not supported"; + case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; + case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; + case PREFIX(corruption_detected): return "Corrupted block detected"; + case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; + case PREFIX(parameter_unsupported): return "Unsupported parameter"; + case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; + case PREFIX(init_missing): return "Context should be init first"; + case PREFIX(memory_allocation): return "Allocation error : not enough memory"; + case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; + case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; + case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; + case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; + case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; + case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; + case PREFIX(dictionary_wrong): return "Dictionary mismatch"; + case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; + case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; + case PREFIX(srcSize_wrong): return "Src size is incorrect"; + case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; + /* following error codes are not stable and may be removed or changed in a future version */ + case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; + case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; + case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; + case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; + case PREFIX(maxCode): + default: return notErrorCode; + } +#endif +} diff --git a/stage1/zstd/lib/common/error_private.h b/stage1/zstd/lib/common/error_private.h new file mode 100644 index 000000000000..007d81066abd --- /dev/null +++ b/stage1/zstd/lib/common/error_private.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* Note : this module is expected to remain private, do not expose it */ + +#ifndef ERROR_H_MODULE +#define ERROR_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* Dependencies +******************************************/ +#include "../zstd_errors.h" /* enum list */ +#include "compiler.h" +#include "debug.h" +#include "zstd_deps.h" /* size_t */ + + +/* **************************************** +* Compiler-specific +******************************************/ +#if defined(__GNUC__) +# define ERR_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define ERR_STATIC static inline +#elif defined(_MSC_VER) +# define ERR_STATIC static __inline +#else +# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + + +/*-**************************************** +* Customization (error_public.h) +******************************************/ +typedef ZSTD_ErrorCode ERR_enum; +#define PREFIX(name) ZSTD_error_##name + + +/*-**************************************** +* Error codes handling +******************************************/ +#undef ERROR /* already defined on Visual Studio */ +#define ERROR(name) ZSTD_ERROR(name) +#define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) + +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } + +ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } + +/* check and forward error code */ +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } + + +/*-**************************************** +* Error Strings +******************************************/ + +const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ + +ERR_STATIC const char* ERR_getErrorName(size_t code) +{ + return ERR_getErrorString(ERR_getErrorCode(code)); +} + +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; +} + +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } + +#define ERR_QUOTE(str) #str + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_H_MODULE */ diff --git a/stage1/zstd/lib/common/fse.h b/stage1/zstd/lib/common/fse.h new file mode 100644 index 000000000000..714bfd3e7f22 --- /dev/null +++ b/stage1/zstd/lib/common/fse.h @@ -0,0 +1,717 @@ +/* ****************************************************************** + * FSE : Finite State Entropy codec + * Public Prototypes declaration + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef FSE_H +#define FSE_H + + +/*-***************************************** +* Dependencies +******************************************/ +#include "zstd_deps.h" /* size_t, ptrdiff_t */ + + +/*-***************************************** +* FSE_PUBLIC_API : control library symbols visibility +******************************************/ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define FSE_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define FSE_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define FSE_PUBLIC_API +#endif + +/*------ Version ------*/ +#define FSE_VERSION_MAJOR 0 +#define FSE_VERSION_MINOR 9 +#define FSE_VERSION_RELEASE 0 + +#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE +#define FSE_QUOTE(str) #str +#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str) +#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION) + +#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE) +FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ + + +/*-**************************************** +* FSE simple functions +******************************************/ +/*! FSE_compress() : + Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. + 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize). + @return : size of compressed data (<= dstCapacity). + Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead. + if FSE_isError(return), compression failed (more details using FSE_getErrorName()) +*/ +FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/*! FSE_decompress(): + Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'dstCapacity'. + @return : size of regenerated data (<= maxDstSize), + or an error code, which can be tested using FSE_isError() . + + ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!! + Why ? : making this distinction requires a header. + Header management is intentionally delegated to the user layer, which can better manage special cases. +*/ +FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize); + + +/*-***************************************** +* Tool functions +******************************************/ +FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */ + +/* Error Management */ +FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */ +FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ + + +/*-***************************************** +* FSE advanced functions +******************************************/ +/*! FSE_compress2() : + Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog' + Both parameters can be defined as '0' to mean : use default value + @return : size of compressed data + Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression. + if FSE_isError(return), it's an error code. +*/ +FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); + + +/*-***************************************** +* FSE detailed API +******************************************/ +/*! +FSE_compress() does the following: +1. count symbol occurrence from source[] into table count[] (see hist.h) +2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) +3. save normalized counters to memory buffer using writeNCount() +4. build encoding table 'CTable' from normalized counters +5. encode the data stream using encoding table 'CTable' + +FSE_decompress() does the following: +1. read normalized counters with readNCount() +2. build decoding table 'DTable' from normalized counters +3. decode the data stream using decoding table 'DTable' + +The following API allows targeting specific sub-functions for advanced tasks. +For example, it's possible to compress several blocks using the same 'CTable', +or to save and provide normalized distribution using external method. +*/ + +/* *** COMPRESSION *** */ + +/*! FSE_optimalTableLog(): + dynamically downsize 'tableLog' when conditions are met. + It saves CPU time, by using smaller tables, while preserving or even improving compression ratio. + @return : recommended tableLog (necessarily <= 'maxTableLog') */ +FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); + +/*! FSE_normalizeCount(): + normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) + 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). + useLowProbCount is a boolean parameter which trades off compressed size for + faster header decoding. When it is set to 1, the compressed data will be slightly + smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be + faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 + is a good default, since header deserialization makes a big speed difference. + Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. + @return : tableLog, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, + const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); + +/*! FSE_NCountWriteBound(): + Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. + Typically useful for allocation purpose. */ +FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_writeNCount(): + Compactly save 'normalizedCounter' into 'buffer'. + @return : size of the compressed table, + or an errorCode, which can be tested using FSE_isError(). */ +FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, + const short* normalizedCounter, + unsigned maxSymbolValue, unsigned tableLog); + +/*! Constructor and Destructor of FSE_CTable. + Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ +typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ +FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); +FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); + +/*! FSE_buildCTable(): + Builds `ct`, which must be already allocated, using FSE_createCTable(). + @return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_compress_usingCTable(): + Compress `src` using `ct` into `dst` which must be already allocated. + @return : size of compressed data (<= `dstCapacity`), + or 0 if compressed data could not fit into `dst`, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct); + +/*! +Tutorial : +---------- +The first step is to count all symbols. FSE_count() does this job very fast. +Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells. +'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0] +maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value) +FSE_count() will return the number of occurrence of the most frequent symbol. +This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). + +The next step is to normalize the frequencies. +FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'. +It also guarantees a minimum of 1 to any Symbol with frequency >= 1. +You can use 'tableLog'==0 to mean "use default tableLog value". +If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(), +which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default"). + +The result of FSE_normalizeCount() will be saved into a table, +called 'normalizedCounter', which is a table of signed short. +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells. +The return value is tableLog if everything proceeded as expected. +It is 0 if there is a single symbol within distribution. +If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()). + +'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount(). +'buffer' must be already allocated. +For guaranteed success, buffer size must be at least FSE_headerBound(). +The result of the function is the number of bytes written into 'buffer'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small). + +'normalizedCounter' can then be used to create the compression table 'CTable'. +The space required by 'CTable' must be already allocated, using FSE_createCTable(). +You can then use FSE_buildCTable() to fill 'CTable'. +If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()). + +'CTable' can then be used to compress 'src', with FSE_compress_usingCTable(). +Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize' +The function returns the size of compressed data (without header), necessarily <= `dstCapacity`. +If it returns '0', compressed data could not fit into 'dst'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). +*/ + + +/* *** DECOMPRESSION *** */ + +/*! FSE_readNCount(): + Read compactly saved 'normalizedCounter' from 'rBuffer'. + @return : size read from 'rBuffer', + or an errorCode, which can be tested using FSE_isError(). + maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ +FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize); + +/*! FSE_readNCount_bmi2(): + * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. + */ +FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize, int bmi2); + +/*! Constructor and Destructor of FSE_DTable. + Note that its size depends on 'tableLog' */ +typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ +FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog); +FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt); + +/*! FSE_buildDTable(): + Builds 'dt', which must be already allocated, using FSE_createDTable(). + return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_decompress_usingDTable(): + Decompress compressed source `cSrc` of size `cSrcSize` using `dt` + into `dst` which must be already allocated. + @return : size of regenerated data (necessarily <= `dstCapacity`), + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); + +/*! +Tutorial : +---------- +(Note : these functions only decompress FSE-compressed blocks. + If block is uncompressed, use memcpy() instead + If block is a single repeated byte, use memset() instead ) + +The first step is to obtain the normalized frequencies of symbols. +This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount(). +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short. +In practice, that means it's necessary to know 'maxSymbolValue' beforehand, +or size the table to handle worst case situations (typically 256). +FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'. +The result of FSE_readNCount() is the number of bytes read from 'rBuffer'. +Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that. +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'. +This is performed by the function FSE_buildDTable(). +The space required by 'FSE_DTable' must be already allocated using FSE_createDTable(). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable(). +`cSrcSize` must be strictly correct, otherwise decompression will fail. +FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) +*/ + +#endif /* FSE_H */ + +#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY) +#define FSE_H_FSE_STATIC_LINKING_ONLY + +/* *** Dependency *** */ +#include "bitstream.h" + + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) + +/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */ +#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable)) +#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable)) + + +/* ***************************************** + * FSE advanced API + ***************************************** */ + +unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); +/**< same as FSE_optimalTableLog(), which used `minus==2` */ + +/* FSE_compress_wksp() : + * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`). + * FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable. + */ +#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) ) +size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); +/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ + +size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); +/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ + +/* FSE_buildCTable_wksp() : + * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). + * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. + * See FSE_buildCTable_wksp() for breakdown of workspace usage. + */ +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) +size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) +#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits); +/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */ + +size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue); +/**< build a fake FSE_DTable, designed to always generate the same symbolValue */ + +#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) +#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize); +/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */ + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); +/**< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */ + +typedef enum { + FSE_repeat_none, /**< Cannot use the previous table */ + FSE_repeat_check, /**< Can use the previous table but it must be checked */ + FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } FSE_repeat; + +/* ***************************************** +* FSE symbol compression API +*******************************************/ +/*! + This API consists of small unitary functions, which highly benefit from being inlined. + Hence their body are included in next section. +*/ +typedef struct { + ptrdiff_t value; + const void* stateTable; + const void* symbolTT; + unsigned stateLog; +} FSE_CState_t; + +static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct); + +static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol); + +static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr); + +/**< +These functions are inner components of FSE_compress_usingCTable(). +They allow the creation of custom streams, mixing multiple tables and bit sources. + +A key property to keep in mind is that encoding and decoding are done **in reverse direction**. +So the first symbol you will encode is the last you will decode, like a LIFO stack. + +You will need a few variables to track your CStream. They are : + +FSE_CTable ct; // Provided by FSE_buildCTable() +BIT_CStream_t bitStream; // bitStream tracking structure +FSE_CState_t state; // State tracking structure (can have several) + + +The first thing to do is to init bitStream and state. + size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize); + FSE_initCState(&state, ct); + +Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError(); +You can then encode your input data, byte after byte. +FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time. +Remember decoding will be done in reverse direction. + FSE_encodeByte(&bitStream, &state, symbol); + +At any time, you can also add any bit sequence. +Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders + BIT_addBits(&bitStream, bitField, nbBits); + +The above methods don't commit data to memory, they just store it into local register, for speed. +Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +Writing data to memory is a manual operation, performed by the flushBits function. + BIT_flushBits(&bitStream); + +Your last FSE encoding operation shall be to flush your last state value(s). + FSE_flushState(&bitStream, &state); + +Finally, you must close the bitStream. +The function returns the size of CStream in bytes. +If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible) +If there is an error, it returns an errorCode (which can be tested using FSE_isError()). + size_t size = BIT_closeCStream(&bitStream); +*/ + + +/* ***************************************** +* FSE symbol decompression API +*******************************************/ +typedef struct { + size_t state; + const void* table; /* precise table may vary, depending on U16 */ +} FSE_DState_t; + + +static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt); + +static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); + +static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); + +/**< +Let's now decompose FSE_decompress_usingDTable() into its unitary components. +You will decode FSE-encoded symbols from the bitStream, +and also any other bitFields you put in, **in reverse order**. + +You will need a few variables to track your bitStream. They are : + +BIT_DStream_t DStream; // Stream context +FSE_DState_t DState; // State context. Multiple ones are possible +FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() + +The first thing to do is to init the bitStream. + errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); + +You should then retrieve your initial state(s) +(in reverse flushing order if you have several ones) : + errorCode = FSE_initDState(&DState, &DStream, DTablePtr); + +You can then decode your data, symbol after symbol. +For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. +Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). + unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); + +You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) +Note : maximum allowed nbBits is 25, for 32-bits compatibility + size_t bitField = BIT_readBits(&DStream, nbBits); + +All above operations only read from local register (which size depends on size_t). +Refueling the register from memory is manually performed by the reload method. + endSignal = FSE_reloadDStream(&DStream); + +BIT_reloadDStream() result tells if there is still some more data to read from DStream. +BIT_DStream_unfinished : there is still some data left into the DStream. +BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. +BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. +BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. + +When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, +to properly detect the exact end of stream. +After each decoded symbol, check if DStream is fully consumed using this simple test : + BIT_reloadDStream(&DStream) >= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +typedef struct { + int deltaFindState; + U32 deltaNbBits; +} FSE_symbolCompressionTransform; /* total 8 bytes */ + +MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) +{ + const void* ptr = ct; + const U16* u16ptr = (const U16*) ptr; + const U32 tableLog = MEM_read16(ptr); + statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; + statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); + statePtr->stateLog = tableLog; +} + + +/*! FSE_initCState2() : +* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) +* uses the smallest state value possible, saving the cost of this symbol */ +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + } +} + +MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) +{ + FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* const stateTable = (const U16*)(statePtr->stateTable); + U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); + BIT_addBits(bitC, statePtr->value, nbBitsOut); + statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; +} + +MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) +{ + BIT_addBits(bitC, statePtr->value, statePtr->stateLog); + BIT_flushBits(bitC); +} + + +/* FSE_getMaxNbBits() : + * Approximate maximum cost of a symbol, in bits. + * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; +} + +/* FSE_bitCost() : + * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; + U32 const threshold = (minNbBits+1) << 16; + assert(tableLog < 16); + assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ + { U32 const tableSize = 1 << tableLog; + U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); + U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ + U32 const bitMultiplier = 1 << accuracyLog; + assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); + assert(normalizedDeltaFromThreshold <= bitMultiplier); + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; + } +} + + +/* ====== Decompression ====== */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#ifndef FSE_MAX_MEMORY_USAGE +# define FSE_MAX_MEMORY_USAGE 14 +#endif +#ifndef FSE_DEFAULT_MEMORY_USAGE +# define FSE_DEFAULT_MEMORY_USAGE 13 +#endif +#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) +# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" +#endif + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#ifndef FSE_MAX_SYMBOL_VALUE +# define FSE_MAX_SYMBOL_VALUE 255 +#endif + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + +#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) + + +#endif /* FSE_STATIC_LINKING_ONLY */ + + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/common/fse_decompress.c b/stage1/zstd/lib/common/fse_decompress.c new file mode 100644 index 000000000000..a5a358015fc9 --- /dev/null +++ b/stage1/zstd/lib/common/fse_decompress.c @@ -0,0 +1,403 @@ +/* ****************************************************************** + * FSE : Finite State Entropy decoder + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* ************************************************************** +* Includes +****************************************************************/ +#include "debug.h" /* assert */ +#include "bitstream.h" +#include "compiler.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#include "error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" + + +/* ************************************************************** +* Error Management +****************************************************************/ +#define FSE_isError ERR_isError +#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ + + +/* ************************************************************** +* Templates +****************************************************************/ +/* + designed to be included + for type-specific functions (template emulation in C) + Objective is to write these functions only once, for improved maintenance +*/ + +/* safety checks */ +#ifndef FSE_FUNCTION_EXTENSION +# error "FSE_FUNCTION_EXTENSION must be defined" +#endif +#ifndef FSE_FUNCTION_TYPE +# error "FSE_FUNCTION_TYPE must be defined" +#endif + +/* Function names */ +#define FSE_CAT(X,Y) X##Y +#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) +#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) + + +/* Function templates */ +FSE_DTable* FSE_createDTable (unsigned tableLog) +{ + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); +} + +void FSE_freeDTable (FSE_DTable* dt) +{ + ZSTD_free(dt); +} + +static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) +{ + void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ + FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); + U16* symbolNext = (U16*)workSpace; + BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); + + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + U32 highThreshold = tableSize-1; + + /* Sanity Checks */ + if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); + if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + + /* Init, lay down lowprob symbols */ + { FSE_DTableHeader DTableH; + DTableH.tableLog = (U16)tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + symbolNext[s] = normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { U32 u; + for (u=0; utableLog = 0; + DTableH->fastMode = 0; + + cell->newState = 0; + cell->symbol = symbolValue; + cell->nbBits = 0; + + return 0; +} + + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSV1 = tableMask+1; + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* Build Decoding Table */ + DTableH->tableLog = (U16)nbBits; + DTableH->fastMode = 1; + for (s=0; s sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[1] = FSE_GETSYMBOL(&state2); + + if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } + + op[2] = FSE_GETSYMBOL(&state1); + + if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[3] = FSE_GETSYMBOL(&state2); + } + + /* tail */ + /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ + while (1) { + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state1); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state2); + break; + } + + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state2); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state1); + break; + } } + + return op-ostart; +} + + +size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize, + const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); + return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); +} + + +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0); +} + +typedef struct { + short ncount[FSE_MAX_SYMBOL_VALUE + 1]; + FSE_DTable dtable[1]; /* Dynamically sized */ +} FSE_DecompressWksp; + + +FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( + void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize, + unsigned maxLog, void* workSpace, size_t wkspSize, + int bmi2) +{ + const BYTE* const istart = (const BYTE*)cSrc; + const BYTE* ip = istart; + unsigned tableLog; + unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; + FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; + + DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); + if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); + + /* normal FSE decoding mode */ + { + size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); + if (FSE_isError(NCountLength)) return NCountLength; + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + assert(NCountLength <= cSrcSize); + ip += NCountLength; + cSrcSize -= NCountLength; + } + + if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); + workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog); + wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + + CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + + { + const void* ptr = wksp->dtable; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); + return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); + } +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); +} +#endif + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); + } +#endif + (void)bmi2; + return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); +} + + +typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { + U32 wksp[FSE_BUILD_DTABLE_WKSP_SIZE_U32(FSE_TABLELOG_ABSOLUTE_MAX, FSE_MAX_SYMBOL_VALUE)]; + return FSE_buildDTable_wksp(dt, normalizedCounter, maxSymbolValue, tableLog, wksp, sizeof(wksp)); +} + +size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) +{ + /* Static analyzer seems unable to understand this table will be properly initialized later */ + U32 wksp[FSE_DECOMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; + return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, FSE_MAX_TABLELOG, wksp, sizeof(wksp)); +} +#endif + + +#endif /* FSE_COMMONDEFS_ONLY */ diff --git a/stage1/zstd/lib/common/huf.h b/stage1/zstd/lib/common/huf.h new file mode 100644 index 000000000000..85518481ec63 --- /dev/null +++ b/stage1/zstd/lib/common/huf.h @@ -0,0 +1,364 @@ +/* ****************************************************************** + * huff0 huffman codec, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef HUF_H_298734234 +#define HUF_H_298734234 + +/* *** Dependencies *** */ +#include "zstd_deps.h" /* size_t */ + + +/* *** library symbols visibility *** */ +/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual, + * HUF symbols remain "private" (internal symbols for library only). + * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define HUF_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define HUF_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */ +#else +# define HUF_PUBLIC_API +#endif + + +/* ========================== */ +/* *** simple functions *** */ +/* ========================== */ + +/** HUF_compress() : + * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'. + * 'dst' buffer must be already allocated. + * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize). + * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB. + * @return : size of compressed data (<= `dstCapacity`). + * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + * if HUF_isError(return), compression failed (more details using HUF_getErrorName()) + */ +HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/** HUF_decompress() : + * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', + * into already allocated buffer 'dst', of minimum size 'dstSize'. + * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data. + * Note : in contrast with FSE, HUF_decompress can regenerate + * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, + * because it knows size to regenerate (originalSize). + * @return : size of regenerated data (== originalSize), + * or an error code, which can be tested using HUF_isError() + */ +HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize); + + +/* *** Tool functions *** */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ + +/* Error Management */ +HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +/* *** Advanced function *** */ + +/** HUF_compress2() : + * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`. + * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX . + * `tableLog` must be `<= HUF_TABLELOG_MAX` . */ +HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog); + +/** HUF_compress4X_wksp() : + * Same as HUF_compress2(), but uses externally allocated `workSpace`. + * `workspace` must be at least as large as HUF_WORKSPACE_SIZE */ +#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) +#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) +HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize); + +#endif /* HUF_H_298734234 */ + +/* ****************************************************************** + * WARNING !! + * The following section contains advanced and experimental definitions + * which shall never be used in the context of a dynamic library, + * because they are not guaranteed to remain stable in the future. + * Only consider them in association with static linking. + * *****************************************************************/ +#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY) +#define HUF_H_HUF_STATIC_LINKING_ONLY + +/* *** Dependencies *** */ +#include "mem.h" /* U32 */ +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" + + +/* *** Constants *** */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ +#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ +#define HUF_SYMBOLVALUE_MAX 255 + +#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) +# error "HUF_TABLELOG_MAX is too large !" +#endif + + +/* **************************************** +* Static allocation +******************************************/ +/* HUF buffer bounds */ +#define HUF_CTABLEBOUND 129 +#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* static allocation of HUF's Compression Table */ +/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ +typedef size_t HUF_CElt; /* consider it an incomplete type */ +#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ + +/* static allocation of HUF's DTable */ +typedef U32 HUF_DTable; +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) +#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } + + +/* **************************************** +* Advanced decompression functions +******************************************/ +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + + +/* **************************************** + * HUF detailed API + * ****************************************/ + +/*! HUF_compress() does the following: + * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") + * 2. (optional) refine tableLog using HUF_optimalTableLog() + * 3. build Huffman table from count using HUF_buildCTable() + * 4. save Huffman table to memory buffer using HUF_writeCTable() + * 5. encode the data stream using HUF_compress4X_usingCTable() + * + * The following API allows targeting specific sub-functions for advanced tasks. + * For example, it's possible to compress several blocks using the same 'CTable', + * or to save and regenerate 'CTable' using external methods. + */ +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); +size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); + +typedef enum { + HUF_repeat_none, /**< Cannot use the previous table */ + HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ + HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } HUF_repeat; +/** HUF_compress4X_repeat() : + * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress4X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); + +/** HUF_buildCTable_wksp() : + * Same as HUF_buildCTable(), but using externally allocated scratch buffer. + * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. + */ +#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) +#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, + const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, + void* workSpace, size_t wkspSize); + +/*! HUF_readStats() : + * Read compact Huffman tree, saved by HUF_writeCTable(). + * `huffWeight` is destination buffer. + * @return : size read from `src` , or an error Code . + * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + +/*! HUF_readStats_wksp() : + * Same as HUF_readStats() but takes an external workspace which must be + * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) +#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workspace, size_t wkspSize, + int bmi2); + +/** HUF_readCTable() : + * Loading a CTable saved with HUF_writeCTable() */ +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); + +/** HUF_getNbBitsFromCTable() : + * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX + * Note 1 : is not inlined, as HUF_CElt definition is private */ +U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); + +/* + * HUF_decompress() does the following: + * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics + * 2. build Huffman table from save, using HUF_readDTableX?() + * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() + */ + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); + +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + + +/* ====================== */ +/* single stream variants */ +/* ====================== */ + +size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U64 U64 */ +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); +/** HUF_compress1X_repeat() : + * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress1X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ +#endif + +size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); +size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif + +#endif /* HUF_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/common/mem.h b/stage1/zstd/lib/common/mem.h new file mode 100644 index 000000000000..85581c38478e --- /dev/null +++ b/stage1/zstd/lib/common/mem.h @@ -0,0 +1,442 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef MEM_H_MODULE +#define MEM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-**************************************** +* Dependencies +******************************************/ +#include /* size_t, ptrdiff_t */ +#include "compiler.h" /* __has_builtin */ +#include "debug.h" /* DEBUG_STATIC_ASSERT */ +#include "zstd_deps.h" /* ZSTD_memcpy */ + + +/*-**************************************** +* Compiler specifics +******************************************/ +#if defined(_MSC_VER) /* Visual Studio */ +# include /* _byteswap_ulong */ +# include /* _byteswap_* */ +#endif +#if defined(__GNUC__) +# define MEM_STATIC static __inline __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline +#else +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + +/*-************************************************************** +* Basic Types +*****************************************************************/ +#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif + typedef uint8_t BYTE; + typedef uint8_t U8; + typedef int8_t S8; + typedef uint16_t U16; + typedef int16_t S16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef int64_t S64; +#else +# include +#if CHAR_BIT != 8 +# error "this implementation requires char to be exactly 8-bit type" +#endif + typedef unsigned char BYTE; + typedef unsigned char U8; + typedef signed char S8; +#if USHRT_MAX != 65535 +# error "this implementation requires short to be exactly 16-bit type" +#endif + typedef unsigned short U16; + typedef signed short S16; +#if UINT_MAX != 4294967295 +# error "this implementation requires int to be exactly 32-bit type" +#endif + typedef unsigned int U32; + typedef signed int S32; +/* note : there are no limits defined for long long type in C90. + * limits exist in C99, however, in such case, is preferred */ + typedef unsigned long long U64; + typedef signed long long S64; +#endif + + +/*-************************************************************** +* Memory I/O API +*****************************************************************/ +/*=== Static platform detection ===*/ +MEM_STATIC unsigned MEM_32bits(void); +MEM_STATIC unsigned MEM_64bits(void); +MEM_STATIC unsigned MEM_isLittleEndian(void); + +/*=== Native unaligned read/write ===*/ +MEM_STATIC U16 MEM_read16(const void* memPtr); +MEM_STATIC U32 MEM_read32(const void* memPtr); +MEM_STATIC U64 MEM_read64(const void* memPtr); +MEM_STATIC size_t MEM_readST(const void* memPtr); + +MEM_STATIC void MEM_write16(void* memPtr, U16 value); +MEM_STATIC void MEM_write32(void* memPtr, U32 value); +MEM_STATIC void MEM_write64(void* memPtr, U64 value); + +/*=== Little endian unaligned read/write ===*/ +MEM_STATIC U16 MEM_readLE16(const void* memPtr); +MEM_STATIC U32 MEM_readLE24(const void* memPtr); +MEM_STATIC U32 MEM_readLE32(const void* memPtr); +MEM_STATIC U64 MEM_readLE64(const void* memPtr); +MEM_STATIC size_t MEM_readLEST(const void* memPtr); + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); + +/*=== Big endian unaligned read/write ===*/ +MEM_STATIC U32 MEM_readBE32(const void* memPtr); +MEM_STATIC U64 MEM_readBE64(const void* memPtr); +MEM_STATIC size_t MEM_readBEST(const void* memPtr); + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); + +/*=== Byteswap ===*/ +MEM_STATIC U32 MEM_swap32(U32 in); +MEM_STATIC U64 MEM_swap64(U64 in); +MEM_STATIC size_t MEM_swapST(size_t in); + + +/*-************************************************************** +* Memory I/O Implementation +*****************************************************************/ +/* MEM_FORCE_MEMORY_ACCESS : + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } +MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } + +MEM_STATIC unsigned MEM_isLittleEndian(void) +{ +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return 1; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return 0; +#elif defined(__clang__) && __LITTLE_ENDIAN__ + return 1; +#elif defined(__clang__) && __BIG_ENDIAN__ + return 0; +#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) + return 1; +#elif defined(__DMC__) && defined(_M_IX86) + return 1; +#else + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +#endif +} + +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } +MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) + __pragma( pack(push, 1) ) + typedef struct { U16 v; } unalign16; + typedef struct { U32 v; } unalign32; + typedef struct { U64 v; } unalign64; + typedef struct { size_t v; } unalignArch; + __pragma( pack(pop) ) +#else + typedef struct { U16 v; } __attribute__((packed)) unalign16; + typedef struct { U32 v; } __attribute__((packed)) unalign32; + typedef struct { U64 v; } __attribute__((packed)) unalign64; + typedef struct { size_t v; } __attribute__((packed)) unalignArch; +#endif + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + +MEM_STATIC U16 MEM_read16(const void* memPtr) +{ + U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U32 MEM_read32(const void* memPtr) +{ + U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U64 MEM_read64(const void* memPtr) +{ + U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC size_t MEM_readST(const void* memPtr) +{ + size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write32(void* memPtr, U32 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write64(void* memPtr, U64 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* MEM_FORCE_MEMORY_ACCESS */ + +MEM_STATIC U32 MEM_swap32(U32 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_ulong(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap32)) + return __builtin_bswap32(in); +#else + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); +#endif +} + +MEM_STATIC U64 MEM_swap64(U64 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_uint64(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap64)) + return __builtin_bswap64(in); +#else + return ((in << 56) & 0xff00000000000000ULL) | + ((in << 40) & 0x00ff000000000000ULL) | + ((in << 24) & 0x0000ff0000000000ULL) | + ((in << 8) & 0x000000ff00000000ULL) | + ((in >> 8) & 0x00000000ff000000ULL) | + ((in >> 24) & 0x0000000000ff0000ULL) | + ((in >> 40) & 0x000000000000ff00ULL) | + ((in >> 56) & 0x00000000000000ffULL); +#endif +} + +MEM_STATIC size_t MEM_swapST(size_t in) +{ + if (MEM_32bits()) + return (size_t)MEM_swap32((U32)in); + else + return (size_t)MEM_swap64((U64)in); +} + +/*=== Little endian r/w ===*/ + +MEM_STATIC U16 MEM_readLE16(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read16(memPtr); + else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)(p[0] + (p[1]<<8)); + } +} + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) +{ + if (MEM_isLittleEndian()) { + MEM_write16(memPtr, val); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val; + p[1] = (BYTE)(val>>8); + } +} + +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); +} + +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) +{ + MEM_writeLE16(memPtr, (U16)val); + ((BYTE*)memPtr)[2] = (BYTE)(val>>16); +} + +MEM_STATIC U32 MEM_readLE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read32(memPtr); + else + return MEM_swap32(MEM_read32(memPtr)); +} + +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, val32); + else + MEM_write32(memPtr, MEM_swap32(val32)); +} + +MEM_STATIC U64 MEM_readLE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read64(memPtr); + else + return MEM_swap64(MEM_read64(memPtr)); +} + +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, val64); + else + MEM_write64(memPtr, MEM_swap64(val64)); +} + +MEM_STATIC size_t MEM_readLEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readLE32(memPtr); + else + return (size_t)MEM_readLE64(memPtr); +} + +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeLE32(memPtr, (U32)val); + else + MEM_writeLE64(memPtr, (U64)val); +} + +/*=== Big endian r/w ===*/ + +MEM_STATIC U32 MEM_readBE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap32(MEM_read32(memPtr)); + else + return MEM_read32(memPtr); +} + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, MEM_swap32(val32)); + else + MEM_write32(memPtr, val32); +} + +MEM_STATIC U64 MEM_readBE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap64(MEM_read64(memPtr)); + else + return MEM_read64(memPtr); +} + +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, MEM_swap64(val64)); + else + MEM_write64(memPtr, val64); +} + +MEM_STATIC size_t MEM_readBEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readBE32(memPtr); + else + return (size_t)MEM_readBE64(memPtr); +} + +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeBE32(memPtr, (U32)val); + else + MEM_writeBE64(memPtr, (U64)val); +} + +/* code only tested on 32 and 64 bits systems */ +MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + + +#if defined (__cplusplus) +} +#endif + +#endif /* MEM_H_MODULE */ diff --git a/stage1/zstd/lib/common/pool.c b/stage1/zstd/lib/common/pool.c new file mode 100644 index 000000000000..2e37cdd73c81 --- /dev/null +++ b/stage1/zstd/lib/common/pool.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* ====== Dependencies ======= */ +#include "zstd_deps.h" /* size_t */ +#include "debug.h" /* assert */ +#include "zstd_internal.h" /* ZSTD_customMalloc, ZSTD_customFree */ +#include "pool.h" + +/* ====== Compiler specifics ====== */ +#if defined(_MSC_VER) +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +#endif + + +#ifdef ZSTD_MULTITHREAD + +#include "threading.h" /* pthread adaptation */ + +/* A job is a function and an opaque argument */ +typedef struct POOL_job_s { + POOL_function function; + void *opaque; +} POOL_job; + +struct POOL_ctx_s { + ZSTD_customMem customMem; + /* Keep track of the threads */ + ZSTD_pthread_t* threads; + size_t threadCapacity; + size_t threadLimit; + + /* The queue is a circular buffer */ + POOL_job *queue; + size_t queueHead; + size_t queueTail; + size_t queueSize; + + /* The number of threads working on jobs */ + size_t numThreadsBusy; + /* Indicates if the queue is empty */ + int queueEmpty; + + /* The mutex protects the queue */ + ZSTD_pthread_mutex_t queueMutex; + /* Condition variable for pushers to wait on when the queue is full */ + ZSTD_pthread_cond_t queuePushCond; + /* Condition variables for poppers to wait on when the queue is empty */ + ZSTD_pthread_cond_t queuePopCond; + /* Indicates if the queue is shutting down */ + int shutdown; +}; + +/* POOL_thread() : + * Work thread for the thread pool. + * Waits for jobs and executes them. + * @returns : NULL on failure else non-null. + */ +static void* POOL_thread(void* opaque) { + POOL_ctx* const ctx = (POOL_ctx*)opaque; + if (!ctx) { return NULL; } + for (;;) { + /* Lock the mutex and wait for a non-empty queue or until shutdown */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + + while ( ctx->queueEmpty + || (ctx->numThreadsBusy >= ctx->threadLimit) ) { + if (ctx->shutdown) { + /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), + * a few threads will be shutdown while !queueEmpty, + * but enough threads will remain active to finish the queue */ + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return opaque; + } + ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); + } + /* Pop a job off the queue */ + { POOL_job const job = ctx->queue[ctx->queueHead]; + ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; + ctx->numThreadsBusy++; + ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); + /* Unlock the mutex, signal a pusher, and run the job */ + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + + job.function(job.opaque); + + /* If the intended queue size was 0, signal after finishing job */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->numThreadsBusy--; + if (ctx->queueSize == 1) { + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + } + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + } + } /* for (;;) */ + assert(0); /* Unreachable */ +} + +/* ZSTD_createThreadPool() : public access point */ +POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { + return POOL_create (numThreads, 0); +} + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem) +{ + POOL_ctx* ctx; + /* Check parameters */ + if (!numThreads) { return NULL; } + /* Allocate the context and zero initialize */ + ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); + if (!ctx) { return NULL; } + /* Initialize the job queue. + * It needs one extra space since one space is wasted to differentiate + * empty and full queues. + */ + ctx->queueSize = queueSize + 1; + ctx->queue = (POOL_job*)ZSTD_customMalloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queueHead = 0; + ctx->queueTail = 0; + ctx->numThreadsBusy = 0; + ctx->queueEmpty = 1; + { + int error = 0; + error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); + if (error) { POOL_free(ctx); return NULL; } + } + ctx->shutdown = 0; + /* Allocate space for the thread handles */ + ctx->threads = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threadCapacity = 0; + ctx->customMem = customMem; + /* Check for errors */ + if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } + /* Initialize the threads */ + { size_t i; + for (i = 0; i < numThreads; ++i) { + if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = i; + POOL_free(ctx); + return NULL; + } } + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + } + return ctx; +} + +/*! POOL_join() : + Shutdown the queue, wake any sleeping threads, and join all of the threads. +*/ +static void POOL_join(POOL_ctx* ctx) { + /* Shut down the queue */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->shutdown = 1; + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + /* Wake up sleeping threads */ + ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + /* Join all of the threads */ + { size_t i; + for (i = 0; i < ctx->threadCapacity; ++i) { + ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */ + } } +} + +void POOL_free(POOL_ctx *ctx) { + if (!ctx) { return; } + POOL_join(ctx); + ZSTD_pthread_mutex_destroy(&ctx->queueMutex); + ZSTD_pthread_cond_destroy(&ctx->queuePushCond); + ZSTD_pthread_cond_destroy(&ctx->queuePopCond); + ZSTD_customFree(ctx->queue, ctx->customMem); + ZSTD_customFree(ctx->threads, ctx->customMem); + ZSTD_customFree(ctx, ctx->customMem); +} + +void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { + POOL_free (pool); +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx) + + ctx->queueSize * sizeof(POOL_job) + + ctx->threadCapacity * sizeof(ZSTD_pthread_t); +} + + +/* @return : 0 on success, 1 on error */ +static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) +{ + if (numThreads <= ctx->threadCapacity) { + if (!numThreads) return 1; + ctx->threadLimit = numThreads; + return 0; + } + /* numThreads > threadCapacity */ + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + if (!threadPool) return 1; + /* replace existing thread pool */ + ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); + ZSTD_customFree(ctx->threads, ctx->customMem); + ctx->threads = threadPool; + /* Initialize additional threads */ + { size_t threadId; + for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { + if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = threadId; + return 1; + } } + } } + /* successfully expanded */ + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + return 0; +} + +/* @return : 0 on success, 1 on error */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads) +{ + int result; + if (ctx==NULL) return 1; + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + result = POOL_resize_internal(ctx, numThreads); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return result; +} + +/** + * Returns 1 if the queue is full and 0 otherwise. + * + * When queueSize is 1 (pool was created with an intended queueSize of 0), + * then a queue is empty if there is a thread free _and_ no job is waiting. + */ +static int isQueueFull(POOL_ctx const* ctx) { + if (ctx->queueSize > 1) { + return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); + } else { + return (ctx->numThreadsBusy == ctx->threadLimit) || + !ctx->queueEmpty; + } +} + + +static void +POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +{ + POOL_job const job = {function, opaque}; + assert(ctx != NULL); + if (ctx->shutdown) return; + + ctx->queueEmpty = 0; + ctx->queue[ctx->queueTail] = job; + ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; + ZSTD_pthread_cond_signal(&ctx->queuePopCond); +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + /* Wait until there is space in the queue for the new job */ + while (isQueueFull(ctx) && (!ctx->shutdown)) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + if (isQueueFull(ctx)) { + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 0; + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 1; +} + + +#else /* ZSTD_MULTITHREAD not defined */ + +/* ========================== */ +/* No multi-threading support */ +/* ========================== */ + + +/* We don't need any data, but if it is empty, malloc() might return NULL. */ +struct POOL_ctx_s { + int dummy; +}; +static POOL_ctx g_poolCtx; + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* +POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) +{ + (void)numThreads; + (void)queueSize; + (void)customMem; + return &g_poolCtx; +} + +void POOL_free(POOL_ctx* ctx) { + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +int POOL_resize(POOL_ctx* ctx, size_t numThreads) { + (void)ctx; (void)numThreads; + return 0; +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); +} + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); + return 1; +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + assert(ctx == &g_poolCtx); + return sizeof(*ctx); +} + +#endif /* ZSTD_MULTITHREAD */ diff --git a/stage1/zstd/lib/common/pool.h b/stage1/zstd/lib/common/pool.h new file mode 100644 index 000000000000..0ebde1805db5 --- /dev/null +++ b/stage1/zstd/lib/common/pool.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef POOL_H +#define POOL_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +#include "zstd_deps.h" +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ +#include "../zstd.h" + +typedef struct POOL_ctx_s POOL_ctx; + +/*! POOL_create() : + * Create a thread pool with at most `numThreads` threads. + * `numThreads` must be at least 1. + * The maximum number of queued jobs before blocking is `queueSize`. + * @return : POOL_ctx pointer on success, else NULL. +*/ +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem); + +/*! POOL_free() : + * Free a thread pool returned by POOL_create(). + */ +void POOL_free(POOL_ctx* ctx); + +/*! POOL_resize() : + * Expands or shrinks pool's number of threads. + * This is more efficient than releasing + creating a new context, + * since it tries to preserve and re-use existing threads. + * `numThreads` must be at least 1. + * @return : 0 when resize was successful, + * !0 (typically 1) if there is an error. + * note : only numThreads can be resized, queueSize remains unchanged. + */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads); + +/*! POOL_sizeof() : + * @return threadpool memory usage + * note : compatible with NULL (returns 0 in this case) + */ +size_t POOL_sizeof(const POOL_ctx* ctx); + +/*! POOL_function : + * The function type that can be added to a thread pool. + */ +typedef void (*POOL_function)(void*); + +/*! POOL_add() : + * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. + * Possibly blocks until there is room in the queue. + * Note : The function may be executed asynchronously, + * therefore, `opaque` must live until function has been completed. + */ +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); + + +/*! POOL_tryAdd() : + * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. + * Returns immediately even if not (does not block). + * @return : 1 if successful, 0 if not. + */ +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); + + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/stage1/zstd/lib/common/portability_macros.h b/stage1/zstd/lib/common/portability_macros.h new file mode 100644 index 000000000000..2143817f5747 --- /dev/null +++ b/stage1/zstd/lib/common/portability_macros.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_PORTABILITY_MACROS_H +#define ZSTD_PORTABILITY_MACROS_H + +/** + * This header file contains macro defintions to support portability. + * This header is shared between C and ASM code, so it MUST only + * contain macro definitions. It MUST not contain any C code. + * + * This header ONLY defines macros to detect platforms/feature support. + * + */ + + +/* compat. with non-clang compilers */ +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +/* detects whether we are being compiled under msan */ +#ifndef ZSTD_MEMORY_SANITIZER +# if __has_feature(memory_sanitizer) +# define ZSTD_MEMORY_SANITIZER 1 +# else +# define ZSTD_MEMORY_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under asan */ +#ifndef ZSTD_ADDRESS_SANITIZER +# if __has_feature(address_sanitizer) +# define ZSTD_ADDRESS_SANITIZER 1 +# elif defined(__SANITIZE_ADDRESS__) +# define ZSTD_ADDRESS_SANITIZER 1 +# else +# define ZSTD_ADDRESS_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under dfsan */ +#ifndef ZSTD_DATAFLOW_SANITIZER +# if __has_feature(dataflow_sanitizer) +# define ZSTD_DATAFLOW_SANITIZER 1 +# else +# define ZSTD_DATAFLOW_SANITIZER 0 +# endif +#endif + +/* Mark the internal assembly functions as hidden */ +#ifdef __ELF__ +# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func +#else +# define ZSTD_HIDE_ASM_FUNCTION(func) +#endif + +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. + */ +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif + +/** + * Only enable assembly for GNUC comptabile compilers, + * because other platforms may not support GAS assembly syntax. + * + * Only enable assembly for Linux / MacOS, other platforms may + * work, but they haven't been tested. This could likely be + * extended to BSD systems. + * + * Disable assembly when MSAN is enabled, because MSAN requires + * 100% of code to be instrumented to work. + */ +#if defined(__GNUC__) +# if defined(__linux__) || defined(__linux) || defined(__APPLE__) +# if ZSTD_MEMORY_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# elif ZSTD_DATAFLOW_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# else +# define ZSTD_ASM_SUPPORTED 1 +# endif +# else +# define ZSTD_ASM_SUPPORTED 0 +# endif +#else +# define ZSTD_ASM_SUPPORTED 0 +#endif + +/** + * Determines whether we should enable assembly for x86-64 + * with BMI2. + * + * Enable if all of the following conditions hold: + * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM + * - Assembly is supported + * - We are compiling for x86-64 and either: + * - DYNAMIC_BMI2 is enabled + * - BMI2 is supported at compile time + */ +#if !defined(ZSTD_DISABLE_ASM) && \ + ZSTD_ASM_SUPPORTED && \ + defined(__x86_64__) && \ + (DYNAMIC_BMI2 || defined(__BMI2__)) +# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 +#else +# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 +#endif + +#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/stage1/zstd/lib/common/threading.c b/stage1/zstd/lib/common/threading.c new file mode 100644 index 000000000000..92cf57c195a5 --- /dev/null +++ b/stage1/zstd/lib/common/threading.c @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/** + * This file will hold wrapper for systems, which do not support pthreads + */ + +#include "threading.h" + +/* create fake symbol to avoid empty translation unit warning */ +int g_ZSTD_threading_useless_symbol; + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html + */ + + +/* === Dependencies === */ +#include +#include + + +/* === Implementation === */ + +static unsigned __stdcall worker(void *arg) +{ + ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg; + thread->arg = thread->start_routine(thread->arg); + return 0; +} + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg) +{ + (void)unused; + thread->arg = arg; + thread->start_routine = start_routine; + thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL); + + if (!thread->handle) + return errno; + else + return 0; +} + +int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) +{ + DWORD result; + + if (!thread.handle) return 0; + + result = WaitForSingleObject(thread.handle, INFINITE); + switch (result) { + case WAIT_OBJECT_0: + if (value_ptr) *value_ptr = thread.arg; + return 0; + case WAIT_ABANDONED: + return EINVAL; + default: + return GetLastError(); + } +} + +#endif /* ZSTD_MULTITHREAD */ + +#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" + +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) +{ + *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); + if (!*mutex) + return 1; + return pthread_mutex_init(*mutex, attr); +} + +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) +{ + if (!*mutex) + return 0; + { + int const ret = pthread_mutex_destroy(*mutex); + ZSTD_free(*mutex); + return ret; + } +} + +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) +{ + *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); + if (!*cond) + return 1; + return pthread_cond_init(*cond, attr); +} + +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) +{ + if (!*cond) + return 0; + { + int const ret = pthread_cond_destroy(*cond); + ZSTD_free(*cond); + return ret; + } +} + +#endif diff --git a/stage1/zstd/lib/common/threading.h b/stage1/zstd/lib/common/threading.h new file mode 100644 index 000000000000..fd0060d5aa2a --- /dev/null +++ b/stage1/zstd/lib/common/threading.h @@ -0,0 +1,155 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef THREADING_H_938743 +#define THREADING_H_938743 + +#include "debug.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html + */ +#ifdef WINVER +# undef WINVER +#endif +#define WINVER 0x0600 + +#ifdef _WIN32_WINNT +# undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#include +#undef ERROR +#define ERROR(name) ZSTD_ERROR(name) + + +/* mutex */ +#define ZSTD_pthread_mutex_t CRITICAL_SECTION +#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) +#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) +#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) +#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) + +/* condition variable */ +#define ZSTD_pthread_cond_t CONDITION_VARIABLE +#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) +#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) +#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) + +/* ZSTD_pthread_create() and ZSTD_pthread_join() */ +typedef struct { + HANDLE handle; + void* (*start_routine)(void*); + void* arg; +} ZSTD_pthread_t; + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg); + +int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr); + +/** + * add here more wrappers as required + */ + + +#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ +/* === POSIX Systems === */ +# include + +#if DEBUGLEVEL < 1 + +#define ZSTD_pthread_mutex_t pthread_mutex_t +#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) +#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) + +#define ZSTD_pthread_cond_t pthread_cond_t +#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) +#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) + +#else /* DEBUGLEVEL >= 1 */ + +/* Debug implementation of threading. + * In this implementation we use pointers for mutexes and condition variables. + * This way, if we forget to init/destroy them the program will crash or ASAN + * will report leaks. + */ + +#define ZSTD_pthread_mutex_t pthread_mutex_t* +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) + +#define ZSTD_pthread_cond_t pthread_cond_t* +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) + +#endif + +#else /* ZSTD_MULTITHREAD not defined */ +/* No multithreading support */ + +typedef int ZSTD_pthread_mutex_t; +#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_mutex_destroy(a) ((void)(a)) +#define ZSTD_pthread_mutex_lock(a) ((void)(a)) +#define ZSTD_pthread_mutex_unlock(a) ((void)(a)) + +typedef int ZSTD_pthread_cond_t; +#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) +#define ZSTD_pthread_cond_signal(a) ((void)(a)) +#define ZSTD_pthread_cond_broadcast(a) ((void)(a)) + +/* do not use ZSTD_pthread_t */ + +#endif /* ZSTD_MULTITHREAD */ + +#if defined (__cplusplus) +} +#endif + +#endif /* THREADING_H_938743 */ diff --git a/stage1/zstd/lib/common/xxhash.c b/stage1/zstd/lib/common/xxhash.c new file mode 100644 index 000000000000..d49497cf1cfa --- /dev/null +++ b/stage1/zstd/lib/common/xxhash.c @@ -0,0 +1,24 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + + +/* + * xxhash.c instantiates functions defined in xxhash.h + */ + +#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ +#define XXH_IMPLEMENTATION /* access definitions */ + +#include "xxhash.h" diff --git a/stage1/zstd/lib/common/xxhash.h b/stage1/zstd/lib/common/xxhash.h new file mode 100644 index 000000000000..8ebbfdd62616 --- /dev/null +++ b/stage1/zstd/lib/common/xxhash.h @@ -0,0 +1,5686 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + +#ifndef XXH_NO_XXH3 +# define XXH_NO_XXH3 +#endif + +#ifndef XXH_NAMESPACE +# define XXH_NAMESPACE ZSTD_ +#endif + +/*! + * @mainpage xxHash + * + * @file xxhash.h + * xxHash prototypes and implementation + */ +/* TODO: update */ +/* Notice extracted from xxHash homepage: + +xxHash is an extremely fast hash algorithm, running at RAM speed limits. +It also successfully passes all tests from the SMHasher suite. + +Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) + +Name Speed Q.Score Author +xxHash 5.4 GB/s 10 +CrapWow 3.2 GB/s 2 Andrew +MurmurHash 3a 2.7 GB/s 10 Austin Appleby +SpookyHash 2.0 GB/s 10 Bob Jenkins +SBox 1.4 GB/s 9 Bret Mulvey +Lookup3 1.2 GB/s 9 Bob Jenkins +SuperFastHash 1.2 GB/s 1 Paul Hsieh +CityHash64 1.05 GB/s 10 Pike & Alakuijala +FNV 0.55 GB/s 5 Fowler, Noll, Vo +CRC32 0.43 GB/s 9 +MD5-32 0.33 GB/s 10 Ronald L. Rivest +SHA1-32 0.28 GB/s 10 + +Q.Score is a measure of quality of the hash function. +It depends on successfully passing SMHasher test set. +10 is a perfect score. + +Note: SMHasher's CRC32 implementation is not the fastest one. +Other speed-oriented implementations can be faster, +especially in combination with PCLMUL instruction: +https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + +A 64-bit version, named XXH64, is available since r35. +It offers much better speed, but for 64-bit applications only. +Name Speed on 64 bits Speed on 32 bits +XXH64 13.8 GB/s 1.9 GB/s +XXH32 6.8 GB/s 6.0 GB/s +*/ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* **************************** + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((unused)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif + + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, + * such as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ + /* Before that, we unconditionally #undef all symbols, + * in case they were already defined with XXH_NAMESPACE. + * They will then be redefined for XXH_INLINE_ALL + */ +# undef XXH_versionNumber + /* XXH32 */ +# undef XXH32 +# undef XXH32_createState +# undef XXH32_freeState +# undef XXH32_reset +# undef XXH32_update +# undef XXH32_digest +# undef XXH32_copyState +# undef XXH32_canonicalFromHash +# undef XXH32_hashFromCanonical + /* XXH64 */ +# undef XXH64 +# undef XXH64_createState +# undef XXH64_freeState +# undef XXH64_reset +# undef XXH64_update +# undef XXH64_digest +# undef XXH64_copyState +# undef XXH64_canonicalFromHash +# undef XXH64_hashFromCanonical + /* XXH3_64bits */ +# undef XXH3_64bits +# undef XXH3_64bits_withSecret +# undef XXH3_64bits_withSeed +# undef XXH3_64bits_withSecretandSeed +# undef XXH3_createState +# undef XXH3_freeState +# undef XXH3_copyState +# undef XXH3_64bits_reset +# undef XXH3_64bits_reset_withSeed +# undef XXH3_64bits_reset_withSecret +# undef XXH3_64bits_update +# undef XXH3_64bits_digest +# undef XXH3_generateSecret + /* XXH3_128bits */ +# undef XXH128 +# undef XXH3_128bits +# undef XXH3_128bits_withSeed +# undef XXH3_128bits_withSecret +# undef XXH3_128bits_reset +# undef XXH3_128bits_reset_withSeed +# undef XXH3_128bits_reset_withSecret +# undef XXH3_128bits_reset_withSecretandSeed +# undef XXH3_128bits_update +# undef XXH3_128bits_digest +# undef XXH128_isEqual +# undef XXH128_cmp +# undef XXH128_canonicalFromHash +# undef XXH128_hashFromCanonical + /* Finally, free the namespace itself */ +# undef XXH_NAMESPACE + + /* employ the namespace for XXH_INLINE_ALL */ +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, + * but they must nonetheless be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and has a more dispersed impact. + * Meanwhile, renaming can be achieved in a single place. + */ +# define XXH_IPREF(Id) XXH_NAMESPACE ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + + + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + + +/*! + * @defgroup public Public API + * Contains details on the public xxHash functions. + * @{ + */ +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Emulate a namespace by transparently prefixing all symbols. + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +# define XXH_NAMESPACE /* YOUR NAME HERE */ +# undef XXH_NAMESPACE +#endif + +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 1 +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) + +/*! + * @brief Obtains the xxHash version. + * + * This is mostly useful when xxHash is compiled as a shared library, + * since the returned value comes from the library, as opposed to header file. + * + * @return `XXH_VERSION_NUMBER` of the invoked library. + */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void); + + +/* **************************** +* Common basic types +******************************/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; + + +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* Don't show include */ +/*! + * @brief An unsigned 32-bit integer. + * + * Not necessarily defined to `uint32_t` but functionally equivalent. + */ +typedef uint32_t XXH32_hash_t; + +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; + +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif + +/*! + * @} + * + * @defgroup xxh32_family XXH32 family + * @ingroup public + * Contains functions used in the classic 32-bit xxHash algorithm. + * + * @note + * XXH32 is useful for older platforms, with no or poor 64-bit performance. + * Note that @ref xxh3_family provides competitive speed + * for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. + * + * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families + * @see @ref xxh32_impl for implementation details + * @{ + */ + +/*! + * @brief Calculates the 32-bit hash of @p input using xxHash32. + * + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 32-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 32-bit hash value. + * + * @see + * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +/*! + * Streaming functions generate the xxHash value from an incremental input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + * + * Example code for incrementally hashing a file: + * @code{.c} + * #include + * #include + * #define BUFFER_SIZE 256 + * + * // Note: XXH64 and XXH3 use the same interface. + * XXH32_hash_t + * hashFile(FILE* stream) + * { + * XXH32_state_t* state; + * unsigned char buf[BUFFER_SIZE]; + * size_t amt; + * XXH32_hash_t hash; + * + * state = XXH32_createState(); // Create a state + * assert(state != NULL); // Error check here + * XXH32_reset(state, 0xbaad5eed); // Reset state with our seed + * while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) { + * XXH32_update(state, buf, amt); // Hash the file in chunks + * } + * hash = XXH32_digest(state); // Finalize the hash + * XXH32_freeState(state); // Clean up + * return hash; + * } + * @endcode + */ + +/*! + * @typedef struct XXH32_state_s XXH32_state_t + * @brief The opaque state struct for the XXH32 streaming API. + * + * @see XXH32_state_s for details. + */ +typedef struct XXH32_state_s XXH32_state_t; + +/*! + * @brief Allocates an @ref XXH32_state_t. + * + * Must be freed with XXH32_freeState(). + * @return An allocated XXH32_state_t on success, `NULL` on failure. + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +/*! + * @brief Frees an @ref XXH32_state_t. + * + * Must be allocated with XXH32_createState(). + * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). + * @return XXH_OK. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +/*! + * @brief Copies one @ref XXH32_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +/*! + * @brief Resets an @ref XXH32_state_t to begin a new hash. + * + * This function resets and seeds a state. Call it before @ref XXH32_update(). + * + * @param statePtr The state struct to reset. + * @param seed The 32-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); + +/*! + * @brief Consumes a block of @p input to an @ref XXH32_state_t. + * + * Call this to incrementally consume blocks of data. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH32_state_t. + * + * @note + * Calling XXH32_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated xxHash32 value from that state. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + */ + +/*! + * @brief Canonical (big endian) representation of @ref XXH32_hash_t. + */ +typedef struct { + unsigned char digest[4]; /*!< Hash bytes, big endian */ +} XXH32_canonical_t; + +/*! + * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. + * + * @param dst The @ref XXH32_canonical_t pointer to be stored to. + * @param hash The @ref XXH32_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); + +/*! + * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. + * + * @param src The @ref XXH32_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +#ifdef __has_attribute +# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define XXH_HAS_ATTRIBUTE(x) 0 +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define XXH_HAS_C_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define XXH_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* +Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute +introduced in CPP17 and C23. +CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough +C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough +*/ +#if XXH_HAS_C_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_CPP_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_ATTRIBUTE(__fallthrough__) +# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) +#else +# define XXH_FALLTHROUGH +#endif + +/*! + * @} + * @ingroup public + * @{ + */ + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* don't include */ +/*! + * @brief An unsigned 64-bit integer. + * + * Not necessarily defined to `uint64_t` but functionally equivalent. + */ +typedef uint64_t XXH64_hash_t; +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else +# include +# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL + /* LP64 ABI says uint64_t is unsigned long */ + typedef unsigned long XXH64_hash_t; +# else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +# endif +#endif + +/*! + * @} + * + * @defgroup xxh64_family XXH64 family + * @ingroup public + * @{ + * Contains functions used in the classic 64-bit xxHash algorithm. + * + * @note + * XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. + * It provides better speed for systems with vector processing capabilities. + */ + + +/*! + * @brief Calculates the 64-bit hash of @p input using xxHash64. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit hash. + * + * @see + * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +/*! + * @brief The opaque state struct for the XXH64 streaming API. + * + * @see XXH64_state_s for details. + */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + +#ifndef XXH_NO_XXH3 +/*! + * @} + * ************************************************************************ + * @defgroup xxh3_family XXH3 family + * @ingroup public + * @{ + * + * XXH3 is a more recent hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * Compared to XXH64, expect XXH3 to run approximately + * ~2x faster on large inputs and >3x faster on small ones, + * exact differences vary depending on platform. + * + * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, + * but does not require it. + * Any 32-bit and 64-bit targets that can run XXH32 smoothly + * can run XXH3 at competitive speeds, even without vector support. + * Further details are explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro. + * + * XXH3 implementation is portable: + * it has a generic C90 formulation that can be compiled on any platform, + * all implementations generage exactly the same hash value on all platforms. + * Starting from v0.8.0, it's also labelled "stable", meaning that + * any future version will also generate the same hash value. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * + * When only 64 bits are needed, prefer invoking the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/*! + * The bare minimum size for a custom secret. + * + * @see + * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), + * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). + */ +#define XXH3_SECRET_SIZE_MIN 136 + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing "XXH3_generateSecret()" instead (see below). + * It will generate a proper high entropy secret derived from the blob of bytes. + * Another advantage of using XXH3_generateSecret() is that + * it guarantees that all bits within the initial blob of bytes + * will impact every bit of the output. + * This is not necessarily the case when using the blob of bytes directly + * because, when hashing _small_ inputs, only a portion of the secret is employed. + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ + +/*! + * @brief The state struct for the XXH3 streaming API. + * + * @see XXH3_state_s for details. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +/*! + * @brief The return value from 128-bit hashes. + * + * Stored in little endian order, although the fields themselves are in native + * endianness. + */ +typedef struct { + XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ + XXH64_hash_t high64; /*!< `value >> 64` */ +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ + +/*! + * @} + */ +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +/*! + * @internal + * @brief Structure for XXH32 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH32_state_t. + * Do not access the members of this struct directly. + * @see XXH64_state_s, XXH3_state_s + */ +struct XXH32_state_s { + XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ + XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ + XXH32_hash_t v[4]; /*!< Accumulator lanes */ + XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ + XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +/*! + * @internal + * @brief Structure for XXH64 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH64_state_t. + * Do not access the members of this struct directly. + * @see XXH32_state_s, XXH3_state_s + */ +struct XXH64_state_s { + XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ + XXH64_hash_t v[4]; /*!< Accumulator lanes */ + XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ + XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ + XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ +}; /* typedef'd to XXH64_state_t */ + + +#ifndef XXH_NO_XXH3 + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ +/* In C++ alignas() is a keyword */ +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +/*! + * @brief The size of the internal XXH3 buffer. + * + * This is the optimal update size for incremental hashing. + * + * @see XXH3_64b_update(), XXH3_128b_update(). + */ +#define XXH3_INTERNALBUFFER_SIZE 256 + +/*! + * @brief Default size of the secret buffer (and @ref XXH3_kSecret). + * + * This is the size used in @ref XXH3_kSecret and the seeded functions. + * + * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. + */ +#define XXH3_SECRET_DEFAULT_SIZE 192 + +/*! + * @internal + * @brief Structure for XXH3 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. + * Otherwise it is an opaque type. + * Never use this definition in combination with dynamic library. + * This allows fields to safely be changed in the future. + * + * @note ** This structure has a strict alignment requirement of 64 bytes!! ** + * Do not allocate this with `malloc()` or `new`, + * it will not be sufficiently aligned. + * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. + * + * Typedef'd to @ref XXH3_state_t. + * Do never access the members of this struct directly. + * + * @see XXH3_INITSTATE() for stack initialization. + * @see XXH3_createState(), XXH3_freeState(). + * @see XXH32_state_s, XXH64_state_s + */ +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + /*!< Used to store a custom secret generated from a seed. */ + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + /*!< The internal buffer. @see XXH32_state_s::mem32 */ + XXH32_hash_t bufferedSize; + /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ + XXH32_hash_t useSeed; + /*!< Reserved field. Needed for padding on 64-bit. */ + size_t nbStripesSoFar; + /*!< Number or stripes processed. */ + XXH64_hash_t totalLen; + /*!< Total length hashed. 64-bit even on 32-bit targets. */ + size_t nbStripesPerBlock; + /*!< Number of stripes per block. */ + size_t secretLimit; + /*!< Size of @ref customSecret or @ref extSecret */ + XXH64_hash_t seed; + /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ + XXH64_hash_t reserved64; + /*!< Reserved field. */ + const unsigned char* extSecret; + /*!< Reference to an external secret for the _withSecret variants, NULL + * for other variants. */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/*! + * @brief Initializes a stack-allocated `XXH3_state_s`. + * + * When the @ref XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* XXH128() : + * simple alias to pre-selected XXH3_128bits variant + */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length @secretSize + * into an already allocated buffer @secretBuffer. + * @secretSize must be >= XXH3_SECRET_SIZE_MIN + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be large enough for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * XXH3_generateSecret() can be employed to ensure proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even "poor entropy" sources such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all required qualities. + * + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize); + + +/* + * XXH3_generateSecret_fromSeed(): + * + * Generate the same secret as the _withSeed() variants. + * + * The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily). + * @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes. + * + * The generated secret can be used in combination with + *`*_withSecret()` and `_withSecretandSeed()` variants. + * This generator is notably useful in combination with `_withSecretandSeed()`, + * as a way to emulate a faster `_withSeed()` variant. + */ +XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed); + +/* + * *_withSecretandSeed() : + * These variants generate hash values using either + * @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) + * or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). + * + * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. + * `_withSeed()` has to generate the secret on the fly for "large" keys. + * It's fast, but can be perceptible for "not so large" keys (< 1 KB). + * `_withSecret()` has to generate the masks on the fly for "small" keys, + * which requires more instructions than _withSeed() variants. + * Therefore, _withSecretandSeed variant combines the best of both worlds. + * + * When @secret has been generated by XXH3_generateSecret_fromSeed(), + * this variant produces *exactly* the same results as `_withSeed()` variant, + * hence offering only a pure speed benefit on "large" input, + * by skipping the need to regenerate the secret for every large input. + * + * Another usage scenario is to hash the secret to a 64-bit hash value, + * for example with XXH3_64bits(), which then becomes the seed, + * and then employ both the seed and the secret in _withSecretandSeed(). + * On top of speed, an added benefit is that each bit in the secret + * has a 50% chance to swap each bit in the output, + * via its impact to the seed. + * This is not guaranteed when using the secret directly in "small data" scenarios, + * because only portions of the secret are employed for small data. + */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed); + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + + +#endif /* XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ + +/*! + * @defgroup tuning Tuning parameters + * @{ + * + * Various macros to control xxHash's behavior. + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Define this to disable 64-bit code. + * + * Useful if only using the @ref xxh32_family and you have a strict C90 compiler. + */ +# define XXH_NO_LONG_LONG +# undef XXH_NO_LONG_LONG /* don't actually */ +/*! + * @brief Controls how unaligned memory is accessed. + * + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * + * @par Possible options: + * + * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` + * @par + * Use `memcpy()`. Safe and portable. Note that most modern compilers will + * eliminate the function call and treat it as an unaligned access. + * + * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))` + * @par + * Depends on compiler extensions and is therefore not portable. + * This method is safe _if_ your compiler supports it, + * and *generally* as fast or faster than `memcpy`. + * + * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast + * @par + * Casts directly and dereferences. This method doesn't depend on the + * compiler, but it violates the C standard as it directly dereferences an + * unaligned pointer. It can generate buggy code on targets which do not + * support unaligned memory accesses, but in some circumstances, it's the + * only known way to get the most performance. + * + * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift + * @par + * Also portable. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. However, some compilers + * will emit literal byteshifts even if the target supports unaligned access. + * . + * + * @warning + * Methods 1 and 2 rely on implementation-defined behavior. Use these with + * care, as what works on one compiler/platform/optimization level may cause + * another to read garbage data or even crash. + * + * See http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. + * + * Prefer these methods in priority order (0 > 3 > 1 > 2) + */ +# define XXH_FORCE_MEMORY_ACCESS 0 + +/*! + * @def XXH_FORCE_ALIGN_CHECK + * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() + * and XXH64() only). + * + * This is an important performance trick for architectures without decent + * unaligned memory access performance. + * + * It checks for input alignment, and when conditions are met, uses a "fast + * path" employing direct 32-bit/64-bit reads, resulting in _dramatically + * faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, + * but not zero. + * + * Moreover, it's not useful to generate an additional code path if memory + * access uses the same instruction for both aligned and unaligned + * addresses (e.g. x86 and aarch64). + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +# define XXH_FORCE_ALIGN_CHECK 0 + +/*! + * @def XXH_NO_INLINE_HINTS + * @brief When non-zero, sets all functions to `static`. + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +# define XXH_NO_INLINE_HINTS 0 + +/*! + * @def XXH32_ENDJMP + * @brief Whether to use a jump for `XXH32_finalize`. + * + * For performance, `XXH32_finalize` uses multiple branches in the finalizer. + * This is generally preferable for performance, + * but depending on exact architecture, a jmp may be preferable. + * + * This setting is only possibly making a difference for very small inputs. + */ +# define XXH32_ENDJMP 0 + +/*! + * @internal + * @brief Redefines old internal names. + * + * For compatibility with code that uses xxHash's internals before the names + * were changed to improve namespacing. There is no other reason to use this. + */ +# define XXH_OLD_NAMES +# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ +#endif /* XXH_DOXYGEN */ +/*! + * @} + */ + +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ + /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */ +# if !defined(__clang__) && \ +( \ + (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + ( \ + defined(__GNUC__) && ( \ + (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ + ( \ + defined(__mips__) && \ + (__mips <= 5 || __mips_isa_rev < 6) && \ + (!defined(__mips16) || defined(__mips_mips16e2)) \ + ) \ + ) \ + ) \ +) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +#ifndef XXH32_ENDJMP +/* generally preferable for performance */ +# define XXH32_ENDJMP 0 +#endif + +/*! + * @defgroup impl Implementation + * @{ + */ + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/* Modify the local functions below should you wish to use some other memory routines */ +/* for ZSTD_malloc(), ZSTD_free() */ +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */ +static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } +static void XXH_free (void* p) { ZSTD_free(p); } +static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + + +/* ************************************* +* Debug +***************************************/ +/*! + * @ingroup tuning + * @def XXH_DEBUGLEVEL + * @brief Sets the debugging level. + * + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#ifndef XXH_STATIC_ASSERT +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# include +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# else +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) +# endif +# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) +#endif + +/*! + * @internal + * @def XXH_COMPILER_GUARD(var) + * @brief Used to prevent unwanted optimizations for @p var. + * + * It uses an empty GCC inline assembly statement with a register constraint + * which forces @p var into a general purpose register (eg eax, ebx, ecx + * on x86) and marks it as modified. + * + * This is used in a few places to avoid unwanted autovectorization (e.g. + * XXH32_round()). All vectorization we want is explicit via intrinsics, + * and _usually_ isn't wanted elsewhere. + * + * We also use it to prevent unwanted constant folding for AArch64 in + * XXH3_initCustomSecret_scalar(). + */ +#if defined(__GNUC__) || defined(__clang__) +# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) +#else +# define XXH_COMPILER_GUARD(var) ((void)0) +#endif + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +/*! + * @internal + * @fn xxh_u32 XXH_read32(const void* ptr) + * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit native endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32(const void* ptr) + * @brief Reads an unaligned 32-bit little endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readBE32(const void* ptr) + * @brief Reads an unaligned 32-bit big endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit big endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) + * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is + * always @ref XXH_alignment::XXH_unaligned. + * + * @param ptr The pointer to read from. + * @param align Whether @p ptr is aligned. + * @pre + * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte + * aligned. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianness *** */ + +/*! + * @ingroup tuning + * @def XXH_CPU_LITTLE_ENDIAN + * @brief Whether the target is little endian. + * + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, + * a runtime check (which is usually constant folded) is used instead. + * + * @note + * This is not necessarily defined to an integer constant. + * + * @see XXH_isLittleEndian() for the runtime check. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/*! + * @internal + * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. + * + * Most compilers will constant fold this. + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +/*! + * @internal + * @def XXH_rotl32(x,r) + * @brief 32-bit rotate left. + * + * @param x The 32-bit integer to be rotated. + * @param r The number of bits to rotate. + * @pre + * @p r > 0 && @p r < 32 + * @note + * @p x and @p r may be evaluated multiple times. + * @return The rotated result. + */ +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +/*! + * @internal + * @fn xxh_u32 XXH_swap32(xxh_u32 x) + * @brief A 32-bit byteswap. + * + * @param x The 32-bit integer to byteswap. + * @return @p x, byteswapped. + */ +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ + +/*! + * @internal + * @brief Enum to indicate whether a pointer is aligned. + */ +typedef enum { + XXH_aligned, /*!< Aligned */ + XXH_unaligned /*!< Possibly unaligned */ +} XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +/*! @ingroup public */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +/*! + * @} + * @defgroup xxh32_impl XXH32 implementation + * @ingroup impl + * @{ + */ + /* #define instead of static const, to be used as initializers */ +#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ +#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ +#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ +#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ +#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +/*! + * @internal + * @brief Normal stripe processing routine. + * + * This shuffles the bits so that any bit from @p input impacts several bits in + * @p acc. + * + * @param acc The accumulator lane. + * @param input The stripe of input to mix. + * @return The mixed accumulator lane. + */ +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if (defined(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * A compiler fence is the only thing that prevents GCC and Clang from + * autovectorizing the XXH32 loop (pragmas and attributes don't work for some + * reason) without globally disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * This is also enabled on AArch64, as Clang autovectorizes it incorrectly + * and it is pointless writing a NEON implementation that is basically the + * same speed as scalar for XXH32. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +/*! + * @internal + * @brief Mixes all bits to finalize the hash. + * + * The final mix ensures that all input bits have a chance to impact any bit in + * the output digest, resulting in an unbiased distribution. + * + * @param h32 The hash to avalanche. + * @return The avalanched hash. + */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +/*! + * @internal + * @brief Processes the last 0-15 bytes of @p ptr. + * + * There may be up to 15 bytes remaining to consume from the input. + * This final stage will digest them to ensure that all input bytes are present + * in the final mix. + * + * @param h32 The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 16. + * @param align Whether @p ptr is aligned. + * @return The finalized hash. + */ +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + if (ptr==NULL) XXH_ASSERT(len == 0); + + /* Compact rerolled version; generally faster */ + if (!XXH32_ENDJMP) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 8: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 9: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 10: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 11: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 7: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 3: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 2: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 1: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH32(). + * + * @param input , len , seed Directly passed from @ref XXH32(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + xxh_u32 h32; + + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=16) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ +/*! + * @ingroup xxh32_family + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + memset(statePtr, 0, sizeof(*statePtr)); + statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + statePtr->v[1] = seed + XXH_PRIME32_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME32_1; + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + + do { + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v[0], 1) + + XXH_rotl32(state->v[1], 7) + + XXH_rotl32(state->v[2], 12) + + XXH_rotl32(state->v[3], 18); + } else { + h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! + * @ingroup xxh32_family + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ +/*! + * @} + * @ingroup impl + * @{ + */ +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + return *(const xxh_u64*) memPtr; +} + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64(xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ +/*! + * @} + * @defgroup xxh64_impl XXH64 implementation + * @ingroup impl + * @{ + */ +/* #define rather that static const, to be used as initializers */ +#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ +#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ +#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ +#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ +#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ + if (ptr==NULL) XXH_ASSERT(len == 0); + len &= 31; + while (len >= 8) { + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); + ptr += 8; + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; + ptr += 4; + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; + --len; + } + return XXH64_avalanche(h64); +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + xxh_u64 h64; + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=32) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 31; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (inputv[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + statePtr->v[1] = seed + XXH_PRIME64_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME64_1; + return XXH_OK; +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); + p += 32 - state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + + do { + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); + h64 = XXH64_mergeRound(h64, state->v[0]); + h64 = XXH64_mergeRound(h64, state->v[1]); + h64 = XXH64_mergeRound(h64, state->v[2]); + h64 = XXH64_mergeRound(h64, state->v[3]); + } else { + h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + +#ifndef XXH_NO_XXH3 + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ +/*! + * @} + * @defgroup xxh3_impl XXH3 implementation + * @ingroup impl + * @{ + */ + +/* === Compiler specifics === */ + +#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ +# define XXH_RESTRICT /* disable */ +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ + || defined(__aarch64__) || defined(_M_ARM) \ + || defined(_M_ARM64) || defined(_M_ARM64EC) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# elif defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# endif +#endif + +#if defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ + +#ifdef XXH_DOXYGEN +/*! + * @ingroup tuning + * @brief Overrides the vectorization implementation chosen for XXH3. + * + * Can be defined to 0 to disable SIMD or any of the values mentioned in + * @ref XXH_VECTOR_TYPE. + * + * If this is not defined, it uses predefined macros to determine the best + * implementation. + */ +# define XXH_VECTOR XXH_SCALAR +/*! + * @ingroup tuning + * @brief Possible values for @ref XXH_VECTOR. + * + * Note that these are actually implemented as macros. + * + * If this is not defined, it is detected automatically. + * @ref XXH_X86DISPATCH overrides this. + */ +enum XXH_VECTOR_TYPE /* fake enum */ { + XXH_SCALAR = 0, /*!< Portable scalar version */ + XXH_SSE2 = 1, /*!< + * SSE2 for Pentium 4, Opteron, all x86_64. + * + * @note SSE2 is also guaranteed on Windows 10, macOS, and + * Android x86. + */ + XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ + XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ + XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */ + XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ +}; +/*! + * @ingroup tuning + * @brief Selects the minimum alignment for XXH3's accumulators. + * + * When using SIMD, this should match the alignment reqired for said vector + * type, so, for example, 32 for AVX2. + * + * Default: Auto detected. + */ +# define XXH_ACC_ALIGN 8 +#endif + +/* Actual definition */ +#ifndef XXH_DOXYGEN +# define XXH_SCALAR 0 +# define XXH_SSE2 1 +# define XXH_AVX2 2 +# define XXH_AVX512 3 +# define XXH_NEON 4 +# define XXH_VSX 5 +#endif + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if ( \ + defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ + || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ + ) && ( \ + defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + ) +# define XXH_VECTOR XXH_NEON +# elif defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/*! + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif + +/*! + * @ingroup tuning + * @brief Controls the NEON to scalar ratio for XXH3 + * + * On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and + * 2 lanes on scalar by default. + * + * This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the + * emulated 64-bit arithmetic is too slow. + * + * Modern ARM CPUs are _very_ sensitive to how their pipelines are used. + * + * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but it can't + * have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions, + * you are only using 2/3 of the CPU bandwidth. + * + * This is even more noticable on the more advanced cores like the A76 which + * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. + * + * Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the + * remaining lanes will use scalar instructions. This improves the bandwidth + * and also gives the integer pipelines something to do besides twiddling loop + * counters and pointers. + * + * This change benefits CPUs with large micro-op buffers without negatively affecting + * other CPUs: + * + * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | + * |:----------------------|:--------------------|----------:|-----------:|------:| + * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | + * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | + * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | + * + * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. + * + * @see XXH3_accumulate_512_neon() + */ +# ifndef XXH3_NEON_LANES +# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ + && !defined(__OPTIMIZE_SIZE__) +# define XXH3_NEON_LANES 6 +# else +# define XXH3_NEON_LANES XXH_ACC_NB +# endif +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# else +/* gcc's altivec.h can have the unwanted consequence to unconditionally + * #define bool, vector, and pixel keywords, + * with bad consequences for programs already using these keywords for other purposes. + * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. + * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, + * but it seems that, in some cases, it isn't. + * Force the build macro to be defined, so that keywords are not altered. + */ +# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) +# define __APPLE_ALTIVEC__ +# endif +# include +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +/*! + * A polyfill for POWER9's vec_revb(). + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/*! + * Performs an unaligned vector load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/*! Pseudorandom secret taken directly from FARSH. */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Calculates a 32-bit to 64-bit long multiply. + * + * Implemented as a macro. + * + * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * @param x, y Numbers to be multiplied + * @return 64-bit product of the low 32 bits of @p x and @p y. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64(xxh_u64 x, xxh_u64 y) +{ + return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/*! + * @brief Calculates a 64->128-bit long multiply. + * + * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar + * version. + * + * @param lhs , rhs The 64-bit integers to be multiplied + * @return The 128-bit result represented in an @ref XXH128_hash_t. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + + /* + * MSVC for ARM64's __umulh method. + * + * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. + */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(__umulh) +#endif + XXH128_hash_t r128; + r128.low64 = lhs * rhs; + r128.high64 = __umulh(lhs, rhs); + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/*! + * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + * + * @param lhs , rhs The 64-bit integers to multiply + * @return The low 64 bits of the product XOR'd by the high 64 bits. + * @see XXH_mult64to128() + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/*! Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + XXH_COMPILER_GUARD(seed64); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + XXH_memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) \ + || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64)); + + const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); + __m512i* const dest = ( __m512i*) customSecret; + int i; + XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 63) == 0); + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards 'const' qualifier". */ + union { + const __m512i* cp; + void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) \ + || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); + + const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); + __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dest); +# endif + XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 31) == 0); + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +/* x86dispatch always generates SSE2 */ +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); +# endif + int i; + + const void* const src16 = XXH3_kSecret; + __m128i* dst16 = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dst16); +# endif + XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dst16 & 15) == 0); + + for (i=0; i < nbRounds; ++i) { + dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +/* forward declarations for the scalar routines */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, size_t lane); + +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, size_t lane); + +/*! + * @internal + * @brief The bulk processing loop for NEON. + * + * The NEON code path is actually partially scalar when running on AArch64. This + * is to optimize the pipelining and can have up to 15% speedup depending on the + * CPU, and it also mitigates some GCC codegen issues. + * + * @see XXH3_NEON_LANES for configuring this and details about this optimization. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); + { + uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8 (xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64 (data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* presumed aligned */ + unsigned int* const xacc = (unsigned int*) acc; + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + /* acc_vec = xacc[i]; */ + xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i); + acc_vec += product; + + /* swap high and low halves */ +#ifdef __s390x__ + acc_vec += vec_permi(data_vec, data_vec, 2); +#else + acc_vec += vec_xxpermdi(data_vec, data_vec, 2); +#endif + /* xacc[i] = acc_vec; */ + vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +/*! + * @internal + * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* xacc = (xxh_u64*) acc; + xxh_u8 const* xinput = (xxh_u8 const*) input; + xxh_u8 const* xsecret = (xxh_u8 const*) secret; + XXH_ASSERT(lane < XXH_ACC_NB); + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + { + xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); + xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ + xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +/*! + * @internal + * @brief Processes a 64 byte block of data using the scalar path. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } +} + +/*! + * @internal + * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + XXH_ASSERT(lane < XXH_ACC_NB); + { + xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); + xxh_u64 acc64 = xacc[lane]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[lane] = acc64; + } +} + +/*! + * @internal + * @brief Scrambles the accumulators after a large chunk has been read + */ +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), it fights for bandwidth with + * the arithmetic instructions. + * + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * + * See XXH3_NEON_LANES for details on the pipsline. + * + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + XXH_COMPILER_GUARD(kSecretPtr); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + XXH_COMPILER_GUARD(result64); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance to transmit secret's size (when it's static) + * so that the compiler can properly optimize the vectorized loop. + * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's preferable for performance that XXH3_hashLong is not inlined, + * as it results in a smaller function for small data, easier to the instruction cache. + * Note that inside this no_inline function, we do inline the internal loop, + * and provide a statically defined secret size to allow optimization of vector loop. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->useSeed = (seed != 0); + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) + XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64) +{ + if (statePtr == NULL) return XXH_ERROR; + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + XXH3_reset_internal(statePtr, seed64, secret, secretSize); + statePtr->useSeed = 1; /* always, even if seed64==0 */ + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +#ifndef XXH3_STREAM_USE_STACK +# ifndef __clang__ /* clang doesn't need additional stack space */ +# define XXH3_STREAM_USE_STACK 1 +# endif +#endif +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* XXH_RESTRICT const state, + const xxh_u8* XXH_RESTRICT input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + XXH_ASSERT(state != NULL); + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* For some reason, gcc and MSVC seem to suffer greatly + * when operating accumulators directly into state. + * Operating into stack space seems to enable proper optimization. + * clang, on the other hand, doesn't seem to need this trick */ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc)); +#else + xxh_u64* XXH_RESTRICT const acc = state->acc; +#endif + state->totalLen += len; + XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); + + /* small input : just fill in tmp buffer */ + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* large input to consume : ingest per full block */ + if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) { + size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; + XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); + /* join to current block's end */ + { size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar; + XXH_ASSERT(nbStripesToEnd <= nbStripes); + XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512); + f_scramble(acc, secret + state->secretLimit); + state->nbStripesSoFar = 0; + input += nbStripesToEnd * XXH_STRIPE_LEN; + nbStripes -= nbStripesToEnd; + } + /* consume per entire blocks */ + while(nbStripes >= state->nbStripesPerBlock) { + XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + state->secretLimit); + input += state->nbStripesPerBlock * XXH_STRIPE_LEN; + nbStripes -= state->nbStripesPerBlock; + } + /* consume last partial block */ + XXH3_accumulate(acc, input, secret, nbStripes, f_acc512); + input += nbStripes * XXH_STRIPE_LEN; + XXH_ASSERT(input < bEnd); /* at least some bytes left */ + state->nbStripesSoFar = nbStripes; + /* buffer predecessor of last partial stripe */ + XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN); + } else { + /* content to consume <= block size */ + /* Consume input by a multiple of internal buffer size */ + if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + } + + /* Some remaining input (always) : buffer it */ + XXH_ASSERT(input < bEnd); + XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); + XXH_ASSERT(state->bufferedSize == 0); + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* save stack accumulators into state */ + memcpy(state->acc, acc, sizeof(acc)); +#endif + } + + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + XXH_memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->useSeed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance to pass @secretLen (when it's static) + * to the compiler, so that it can properly optimize the vectorized loop. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All initialization and update functions are identical to 64-bit streaming variant. + * The only difference is the finalization routine. + */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + return XXH3_64bits_reset(statePtr); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSeed(statePtr, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); + XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +/* ========================================== + * Secret generators + * ========================================== + */ +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) +{ + XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); + XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize) +{ +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(secretBuffer != NULL); + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); +#else + /* production mode, assert() are disabled */ + if (secretBuffer == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; +#endif + + if (customSeedSize == 0) { + customSeed = XXH3_kSecret; + customSeedSize = XXH_SECRET_DEFAULT_SIZE; + } +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(customSeed != NULL); +#else + if (customSeed == NULL) return XXH_ERROR; +#endif + + /* Fill secretBuffer with a copy of customSeed - repeat as needed */ + { size_t pos = 0; + while (pos < secretSize) { + size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); + memcpy((char*)secretBuffer + pos, customSeed, toCopy); + pos += toCopy; + } } + + { size_t const nbSeg16 = secretSize / 16; + size_t n; + XXH128_canonical_t scrambler; + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + for (n=0; n +#include +#include + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) +#else +# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) memset((p),(v),(l)) +#endif + +#endif /* ZSTD_DEPS_COMMON */ + +/* Need: + * ZSTD_malloc() + * ZSTD_free() + * ZSTD_calloc() + */ +#ifdef ZSTD_DEPS_NEED_MALLOC +#ifndef ZSTD_DEPS_MALLOC +#define ZSTD_DEPS_MALLOC + +#include + +#define ZSTD_malloc(s) malloc(s) +#define ZSTD_calloc(n,s) calloc((n), (s)) +#define ZSTD_free(p) free((p)) + +#endif /* ZSTD_DEPS_MALLOC */ +#endif /* ZSTD_DEPS_NEED_MALLOC */ + +/* + * Provides 64-bit math support. + * Need: + * U64 ZSTD_div64(U64 dividend, U32 divisor) + */ +#ifdef ZSTD_DEPS_NEED_MATH64 +#ifndef ZSTD_DEPS_MATH64 +#define ZSTD_DEPS_MATH64 + +#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) + +#endif /* ZSTD_DEPS_MATH64 */ +#endif /* ZSTD_DEPS_NEED_MATH64 */ + +/* Need: + * assert() + */ +#ifdef ZSTD_DEPS_NEED_ASSERT +#ifndef ZSTD_DEPS_ASSERT +#define ZSTD_DEPS_ASSERT + +#include + +#endif /* ZSTD_DEPS_ASSERT */ +#endif /* ZSTD_DEPS_NEED_ASSERT */ + +/* Need: + * ZSTD_DEBUG_PRINT() + */ +#ifdef ZSTD_DEPS_NEED_IO +#ifndef ZSTD_DEPS_IO +#define ZSTD_DEPS_IO + +#include +#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) + +#endif /* ZSTD_DEPS_IO */ +#endif /* ZSTD_DEPS_NEED_IO */ + +/* Only requested when is known to be present. + * Need: + * intptr_t + */ +#ifdef ZSTD_DEPS_NEED_STDINT +#ifndef ZSTD_DEPS_STDINT +#define ZSTD_DEPS_STDINT + +#include + +#endif /* ZSTD_DEPS_STDINT */ +#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/stage1/zstd/lib/common/zstd_internal.h b/stage1/zstd/lib/common/zstd_internal.h new file mode 100644 index 000000000000..e4d36ce09051 --- /dev/null +++ b/stage1/zstd/lib/common/zstd_internal.h @@ -0,0 +1,493 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_CCOMMON_H_MODULE +#define ZSTD_CCOMMON_H_MODULE + +/* this module contains definitions which must be identical + * across compression, decompression and dictBuilder. + * It also contains a few functions useful to at least 2 of them + * and which benefit from being inlined */ + +/*-************************************* +* Dependencies +***************************************/ +#include "compiler.h" +#include "cpu.h" +#include "mem.h" +#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ +#include "error_private.h" +#define ZSTD_STATIC_LINKING_ONLY +#include "../zstd.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "huf.h" +#ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +#endif +#include "xxhash.h" /* XXH_reset, update, digest */ +#ifndef ZSTD_NO_TRACE +# include "zstd_trace.h" +#else +# define ZSTD_TRACE 0 +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ---- static assert (debug) --- */ +#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) +#define ZSTD_isError ERR_isError /* for inlining */ +#define FSE_isError ERR_isError +#define HUF_isError ERR_isError + + +/*-************************************* +* shared macros +***************************************/ +#undef MIN +#undef MAX +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) + + +/*-************************************* +* Common constants +***************************************/ +#define ZSTD_OPT_NUM (1<<12) + +#define ZSTD_REP_NUM 3 /* number of repcodes */ +static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define BIT7 128 +#define BIT6 64 +#define BIT5 32 +#define BIT4 16 +#define BIT1 2 +#define BIT0 1 + +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 +static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; + +#define ZSTD_FRAMEIDSIZE 4 /* magic number size */ + +#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ +static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; + +#define ZSTD_FRAMECHECKSUMSIZE 4 + +#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ + +#define HufLog 12 +typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; + +#define LONGNBSEQ 0x7F00 + +#define MINMATCH 3 + +#define Litbits 8 +#define MaxLit ((1<= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); + /* Separate out the first COPY16() call because the copy length is + * almost certain to be short, so the branches have different + * probabilities. Since it is almost certain to be short, only do + * one COPY16() in the first call. Then, do two calls per loop since + * at that point it is more likely to have a high trip count. + */ +#ifdef __aarch64__ + do { + COPY16(op, ip); + } + while (op < oend); +#else + ZSTD_copy16(op, ip); + if (16 >= length) return; + op += 16; + ip += 16; + do { + COPY16(op, ip); + COPY16(op, ip); + } + while (op < oend); +#endif + } +} + +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + size_t const length = MIN(dstCapacity, srcSize); + if (length > 0) { + ZSTD_memcpy(dst, src, length); + } + return length; +} + +/* define "workspace is too large" as this number of times larger than needed */ +#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 + +/* when workspace is continuously too large + * during at least this number of times, + * context's memory usage is considered wasteful, + * because it's sized to handle a worst case scenario which rarely happens. + * In which case, resize it down to free some memory */ +#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 + +/* Controls whether the input/output buffer is buffered or stable. */ +typedef enum { + ZSTD_bm_buffered = 0, /* Buffer the input/output */ + ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ +} ZSTD_bufferMode_e; + + +/*-******************************************* +* Private declarations +*********************************************/ +typedef struct seqDef_s { + U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ + U16 litLength; + U16 mlBase; /* mlBase == matchLength - MINMATCH */ +} seqDef; + +/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ +typedef enum { + ZSTD_llt_none = 0, /* no longLengthType */ + ZSTD_llt_literalLength = 1, /* represents a long literal */ + ZSTD_llt_matchLength = 2 /* represents a long match */ +} ZSTD_longLengthType_e; + +typedef struct { + seqDef* sequencesStart; + seqDef* sequences; /* ptr to end of sequences */ + BYTE* litStart; + BYTE* lit; /* ptr to end of literals */ + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; + size_t maxNbSeq; + size_t maxNbLit; + + /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength + * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment + * the existing value of the litLength or matchLength by 0x10000. + */ + ZSTD_longLengthType_e longLengthType; + U32 longLengthPos; /* Index of the sequence to apply long length modification to */ +} seqStore_t; + +typedef struct { + U32 litLength; + U32 matchLength; +} ZSTD_sequenceLength; + +/** + * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences + * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. + */ +MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) +{ + ZSTD_sequenceLength seqLen; + seqLen.litLength = seq->litLength; + seqLen.matchLength = seq->mlBase + MINMATCH; + if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { + seqLen.litLength += 0xFFFF; + } + if (seqStore->longLengthType == ZSTD_llt_matchLength) { + seqLen.matchLength += 0xFFFF; + } + } + return seqLen; +} + +/** + * Contains the compressed frame size and an upper-bound for the decompressed frame size. + * Note: before using `compressedSize`, check for errors using ZSTD_isError(). + * similarly, before using `decompressedBound`, check for errors using: + * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` + */ +typedef struct { + size_t compressedSize; + unsigned long long decompressedBound; +} ZSTD_frameSizeInfo; /* decompress & legacy */ + +const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ + +/* custom memory allocation functions */ +void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem); +void ZSTD_customFree(void* ptr, ZSTD_customMem customMem); + + +MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ +# if STATIC_BMI2 == 1 + return _lzcnt_u32(val)^31; +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; +# endif + } +} + +/** + * Counts the number of trailing zeros of a `size_t`. + * Most compilers should support CTZ as a builtin. A backup + * implementation is provided if the builtin isn't supported, but + * it may not be terribly efficient. + */ +MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val) +{ + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 + return _tzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward64(&r, (U64)val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return __builtin_ctzll((U64)val); +# else + static const int DeBruijnBytePos[64] = { 0, 1, 2, 7, 3, 13, 8, 19, + 4, 25, 14, 28, 9, 34, 20, 56, + 5, 17, 26, 54, 15, 41, 29, 43, + 10, 31, 38, 35, 21, 45, 49, 57, + 63, 6, 12, 18, 24, 27, 33, 55, + 16, 53, 40, 42, 30, 37, 44, 48, + 62, 11, 23, 32, 52, 39, 36, 47, + 61, 22, 51, 46, 60, 50, 59, 58 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + if (val != 0) { + unsigned long r; + _BitScanForward(&r, (U32)val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return __builtin_ctz((U32)val); +# else + static const int DeBruijnBytePos[32] = { 0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, + 26, 12, 18, 6, 11, 5, 10, 9 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } +} + + +/* ZSTD_invalidateRepCodes() : + * ensures next compression will not use repcodes from previous block. + * Note : only works with regular variant; + * do not use with extDict variant ! */ +void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */ + + +typedef struct { + blockType_e blockType; + U32 lastBlock; + U32 origSize; +} blockProperties_t; /* declared here for decompress and fullbench */ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr); + +/*! ZSTD_decodeSeqHeaders() : + * decode sequence header from src */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize); + +/** + * @returns true iff the CPU supports dynamic BMI2 dispatch. + */ +MEM_STATIC int ZSTD_cpuSupportsBmi2(void) +{ + ZSTD_cpuid_t cpuid = ZSTD_cpuid(); + return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/stage1/zstd/lib/common/zstd_trace.h b/stage1/zstd/lib/common/zstd_trace.h new file mode 100644 index 000000000000..f9121f7d8ed5 --- /dev/null +++ b/stage1/zstd/lib/common/zstd_trace.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_TRACE_H +#define ZSTD_TRACE_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include + +/* weak symbol support + * For now, enable conservatively: + * - Only GNUC + * - Only ELF + * - Only x86-64 and i386 + * Also, explicitly disable on platforms known not to work so they aren't + * forgotten in the future. + */ +#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ + defined(__GNUC__) && defined(__ELF__) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ + !defined(__CYGWIN__) && !defined(_AIX) +# define ZSTD_HAVE_WEAK_SYMBOLS 1 +#else +# define ZSTD_HAVE_WEAK_SYMBOLS 0 +#endif +#if ZSTD_HAVE_WEAK_SYMBOLS +# define ZSTD_WEAK_ATTR __attribute__((__weak__)) +#else +# define ZSTD_WEAK_ATTR +#endif + +/* Only enable tracing when weak symbols are available. */ +#ifndef ZSTD_TRACE +# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS +#endif + +#if ZSTD_TRACE + +struct ZSTD_CCtx_s; +struct ZSTD_DCtx_s; +struct ZSTD_CCtx_params_s; + +typedef struct { + /** + * ZSTD_VERSION_NUMBER + * + * This is guaranteed to be the first member of ZSTD_trace. + * Otherwise, this struct is not stable between versions. If + * the version number does not match your expectation, you + * should not interpret the rest of the struct. + */ + unsigned version; + /** + * Non-zero if streaming (de)compression is used. + */ + unsigned streaming; + /** + * The dictionary ID. + */ + unsigned dictionaryID; + /** + * Is the dictionary cold? + * Only set on decompression. + */ + unsigned dictionaryIsCold; + /** + * The dictionary size or zero if no dictionary. + */ + size_t dictionarySize; + /** + * The uncompressed size of the data. + */ + size_t uncompressedSize; + /** + * The compressed size of the data. + */ + size_t compressedSize; + /** + * The fully resolved CCtx parameters (NULL on decompression). + */ + struct ZSTD_CCtx_params_s const* params; + /** + * The ZSTD_CCtx pointer (NULL on decompression). + */ + struct ZSTD_CCtx_s const* cctx; + /** + * The ZSTD_DCtx pointer (NULL on compression). + */ + struct ZSTD_DCtx_s const* dctx; +} ZSTD_Trace; + +/** + * A tracing context. It must be 0 when tracing is disabled. + * Otherwise, any non-zero value returned by a tracing begin() + * function is presented to any subsequent calls to end(). + * + * Any non-zero value is treated as tracing is enabled and not + * interpreted by the library. + * + * Two possible uses are: + * * A timestamp for when the begin() function was called. + * * A unique key identifying the (de)compression, like the + * address of the [dc]ctx pointer if you need to track + * more information than just a timestamp. + */ +typedef unsigned long long ZSTD_TraceCtx; + +/** + * Trace the beginning of a compression call. + * @param cctx The dctx pointer for the compression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( + struct ZSTD_CCtx_s const* cctx); + +/** + * Trace the end of a compression call. + * @param ctx The return value of ZSTD_trace_compress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +/** + * Trace the beginning of a decompression call. + * @param dctx The dctx pointer for the decompression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( + struct ZSTD_DCtx_s const* dctx); + +/** + * Trace the end of a decompression call. + * @param ctx The return value of ZSTD_trace_decompress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +#endif /* ZSTD_TRACE */ + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_TRACE_H */ diff --git a/stage1/zstd/lib/decompress/huf_decompress.c b/stage1/zstd/lib/decompress/huf_decompress.c new file mode 100644 index 000000000000..2027188255e1 --- /dev/null +++ b/stage1/zstd/lib/decompress/huf_decompress.c @@ -0,0 +1,1889 @@ +/* ****************************************************************** + * huff0 huffman decoder, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************************************** +* Dependencies +****************************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include "../common/compiler.h" +#include "../common/bitstream.h" /* BIT_* */ +#include "../common/fse.h" /* to compress headers */ +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/error_private.h" +#include "../common/zstd_internal.h" + +/* ************************************************************** +* Constants +****************************************************************/ + +#define HUF_DECODER_FAST_TABLELOG 11 + +/* ************************************************************** +* Macros +****************************************************************/ + +/* These two optional macros force the use one way or another of the two + * Huffman decompression implementations. You can't force in both directions + * at the same time. + */ +#if defined(HUF_FORCE_DECOMPRESS_X1) && \ + defined(HUF_FORCE_DECOMPRESS_X2) +#error "Cannot force the use of the X1 and X2 decoders at the same time!" +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && DYNAMIC_BMI2 +# define HUF_ASM_X86_64_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE +#else +# define HUF_ASM_X86_64_BMI2_ATTRS +#endif + +#ifdef __cplusplus +# define HUF_EXTERN_C extern "C" +#else +# define HUF_EXTERN_C +#endif +#define HUF_ASM_DECL HUF_EXTERN_C + +#if DYNAMIC_BMI2 || (ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_BMI2_FUNCTION 1 +#else +# define HUF_NEED_BMI2_FUNCTION 0 +#endif + +#if !(ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_DEFAULT_FUNCTION 1 +#else +# define HUF_NEED_DEFAULT_FUNCTION 0 +#endif + +/* ************************************************************** +* Error Management +****************************************************************/ +#define HUF_isError ERR_isError + + +/* ************************************************************** +* Byte alignment for workSpace management +****************************************************************/ +#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) +#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + + +/* ************************************************************** +* BMI2 Variant Wrappers +****************************************************************/ +#if DYNAMIC_BMI2 + +#define HUF_DGEN(fn) \ + \ + static size_t fn##_default( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + { \ + if (bmi2) { \ + return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#else + +#define HUF_DGEN(fn) \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + { \ + (void)bmi2; \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#endif + + +/*-***************************/ +/* generic DTableDesc */ +/*-***************************/ +typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc; + +static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) +{ + DTableDesc dtd; + ZSTD_memcpy(&dtd, table, sizeof(dtd)); + return dtd; +} + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +static size_t HUF_initDStream(BYTE const* ip) { + BYTE const lastByte = ip[7]; + size_t const bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + size_t const value = MEM_readLEST(ip) | 1; + assert(bitsConsumed <= 8); + return value << bitsConsumed; +} +typedef struct { + BYTE const* ip[4]; + BYTE* op[4]; + U64 bits[4]; + void const* dt; + BYTE const* ilimit; + BYTE* oend; + BYTE const* iend[4]; +} HUF_DecompressAsmArgs; + +/** + * Initializes args for the asm decoding loop. + * @returns 0 on success + * 1 if the fallback implementation should be used. + * Or an error code on failure. + */ +static size_t HUF_DecompressAsmArgs_init(HUF_DecompressAsmArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; + + const BYTE* const ilimit = (const BYTE*)src + 6 + 8; + + BYTE* const oend = (BYTE*)dst + dstSize; + + /* The following condition is false on x32 platform, + * but HUF_asm is not compatible with this ABI */ + if (!(MEM_isLittleEndian() && !MEM_32bits())) return 1; + + /* strict minimum : jump table + 1 byte per stream */ + if (srcSize < 10) + return ERROR(corruption_detected); + + /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. + * If table log is not correct at this point, fallback to the old decoder. + * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. + */ + if (dtLog != HUF_DECODER_FAST_TABLELOG) + return 1; + + /* Read the jump table. */ + { + const BYTE* const istart = (const BYTE*)src; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = srcSize - (length1 + length2 + length3 + 6); + args->iend[0] = istart + 6; /* jumpTable */ + args->iend[1] = args->iend[0] + length1; + args->iend[2] = args->iend[1] + length2; + args->iend[3] = args->iend[2] + length3; + + /* HUF_initDStream() requires this, and this small of an input + * won't benefit from the ASM loop anyways. + * length1 must be >= 16 so that ip[0] >= ilimit before the loop + * starts. + */ + if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8) + return 1; + if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ + } + /* ip[] contains the position that is currently loaded into bits[]. */ + args->ip[0] = args->iend[1] - sizeof(U64); + args->ip[1] = args->iend[2] - sizeof(U64); + args->ip[2] = args->iend[3] - sizeof(U64); + args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); + + /* op[] contains the output pointers. */ + args->op[0] = (BYTE*)dst; + args->op[1] = args->op[0] + (dstSize+3)/4; + args->op[2] = args->op[1] + (dstSize+3)/4; + args->op[3] = args->op[2] + (dstSize+3)/4; + + /* No point to call the ASM loop for tiny outputs. */ + if (args->op[3] >= oend) + return 1; + + /* bits[] is the bit container. + * It is read from the MSB down to the LSB. + * It is shifted left as it is read, and zeros are + * shifted in. After the lowest valid bit a 1 is + * set, so that CountTrailingZeros(bits[]) can be used + * to count how many bits we've consumed. + */ + args->bits[0] = HUF_initDStream(args->ip[0]); + args->bits[1] = HUF_initDStream(args->ip[1]); + args->bits[2] = HUF_initDStream(args->ip[2]); + args->bits[3] = HUF_initDStream(args->ip[3]); + + /* If ip[] >= ilimit, it is guaranteed to be safe to + * reload bits[]. It may be beyond its section, but is + * guaranteed to be valid (>= istart). + */ + args->ilimit = ilimit; + + args->oend = oend; + args->dt = dt; + + return 0; +} + +static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressAsmArgs const* args, int stream, BYTE* segmentEnd) +{ + /* Validate that we haven't overwritten. */ + if (args->op[stream] > segmentEnd) + return ERROR(corruption_detected); + /* Validate that we haven't read beyond iend[]. + * Note that ip[] may be < iend[] because the MSB is + * the next bit to read, and we may have consumed 100% + * of the stream, so down to iend[i] - 8 is valid. + */ + if (args->ip[stream] < args->iend[stream] - 8) + return ERROR(corruption_detected); + + /* Construct the BIT_DStream_t. */ + bit->bitContainer = MEM_readLE64(args->ip[stream]); + bit->bitsConsumed = ZSTD_countTrailingZeros((size_t)args->bits[stream]); + bit->start = (const char*)args->iend[0]; + bit->limitPtr = bit->start + sizeof(size_t); + bit->ptr = (const char*)args->ip[stream]; + + return 0; +} +#endif + + +#ifndef HUF_FORCE_DECOMPRESS_X2 + +/*-***************************/ +/* single-symbol decoding */ +/*-***************************/ +typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ + +/** + * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at + * a time. + */ +static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { + U64 D4; + if (MEM_isLittleEndian()) { + D4 = (symbol << 8) + nbBits; + } else { + D4 = symbol + (nbBits << 8); + } + D4 *= 0x0001000100010001ULL; + return D4; +} + +/** + * Increase the tableLog to targetTableLog and rescales the stats. + * If tableLog > targetTableLog this is a no-op. + * @returns New tableLog + */ +static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) +{ + if (tableLog > targetTableLog) + return tableLog; + if (tableLog < targetTableLog) { + U32 const scale = targetTableLog - tableLog; + U32 s; + /* Increase the weight for all non-zero probability symbols by scale. */ + for (s = 0; s < nbSymbols; ++s) { + huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); + } + /* Update rankVal to reflect the new weights. + * All weights except 0 get moved to weight + scale. + * Weights [1, scale] are empty. + */ + for (s = targetTableLog; s > scale; --s) { + rankVal[s] = rankVal[s - scale]; + } + for (s = scale; s > 0; --s) { + rankVal[s] = 0; + } + } + return targetTableLog; +} + +typedef struct { + U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; + BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; +} HUF_ReadDTableX1_Workspace; + + +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) +{ + return HUF_readDTableX1_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + U32 tableLog = 0; + U32 nbSymbols = 0; + size_t iSize; + void* const dtPtr = DTable + 1; + HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; + HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; + + DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); + if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); + + DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); + /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), bmi2); + if (HUF_isError(iSize)) return iSize; + + + /* Table header */ + { DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 const maxTableLog = dtd.maxTableLog + 1; + U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); + tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); + if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ + dtd.tableType = 0; + dtd.tableLog = (BYTE)tableLog; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + } + + /* Compute symbols and rankStart given rankVal: + * + * rankVal already contains the number of values of each weight. + * + * symbols contains the symbols ordered by weight. First are the rankVal[0] + * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. + * symbols[0] is filled (but unused) to avoid a branch. + * + * rankStart contains the offset where each rank belongs in the DTable. + * rankStart[0] is not filled because there are no entries in the table for + * weight 0. + */ + { + int n; + int nextRankStart = 0; + int const unroll = 4; + int const nLimit = (int)nbSymbols - unroll + 1; + for (n=0; n<(int)tableLog+1; n++) { + U32 const curr = nextRankStart; + nextRankStart += wksp->rankVal[n]; + wksp->rankStart[n] = curr; + } + for (n=0; n < nLimit; n += unroll) { + int u; + for (u=0; u < unroll; ++u) { + size_t const w = wksp->huffWeight[n+u]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); + } + } + for (; n < (int)nbSymbols; ++n) { + size_t const w = wksp->huffWeight[n]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; + } + } + + /* fill DTable + * We fill all entries of each weight in order. + * That way length is a constant for each iteration of the outer loop. + * We can switch based on the length to a different inner loop which is + * optimized for that particular case. + */ + { + U32 w; + int symbol=wksp->rankVal[0]; + int rankStart=0; + for (w=1; wrankVal[w]; + int const length = (1 << w) >> 1; + int uStart = rankStart; + BYTE const nbBits = (BYTE)(tableLog + 1 - w); + int s; + int u; + switch (length) { + case 1: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart] = D; + uStart += 1; + } + break; + case 2: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart+0] = D; + dt[uStart+1] = D; + uStart += 2; + } + break; + case 4: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + uStart += 4; + } + break; + case 8: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + MEM_write64(dt + uStart + 4, D4); + uStart += 8; + } + break; + default: + for (s=0; ssymbols[symbol + s], nbBits); + for (u=0; u < length; u += 16) { + MEM_write64(dt + uStart + u + 0, D4); + MEM_write64(dt + uStart + u + 4, D4); + MEM_write64(dt + uStart + u + 8, D4); + MEM_write64(dt + uStart + u + 12, D4); + } + assert(u == length); + uStart += length; + } + break; + } + symbol += symbolCount; + rankStart += symbolCount * length; + } + } + return iSize; +} + +FORCE_INLINE_TEMPLATE BYTE +HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ + BYTE const c = dt[val].byte; + BIT_skipBits(Dstream, dt[val].nbBits); + return c; +} + +#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \ + *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +HINT_INLINE size_t +HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 4 symbols at a time */ + if ((pEnd - p) > 3) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* [0-3] symbols remaining */ + if (MEM_32bits()) + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd)) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + /* no more data to retrieve from bitstream, no need to reload */ + while (p < pEnd) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + return pEnd-pStart; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BYTE* op = (BYTE*)dst; + BYTE* const oend = op + dstSize; + const void* dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + BIT_DStream_t bitD; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog); + + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + return dstSize; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + /* Check */ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - 3; + const void* const dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + U32 endSignal = 1; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + } + } + + /* check corruption */ + /* note : should not be necessary : op# advance in lock step, and we control op4. + * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS +size_t +HUF_decompress4X1_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(&args); + + /* Our loop guarantees that ip[] >= ilimit and that we haven't + * overwritten any op[]. + */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bit streams one by one. */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + /* Decompress and validate that we've produced exactly the expected length. */ + args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ + +typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); + +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) + +static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X1_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} + + +size_t HUF_decompress1X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} + + +size_t HUF_decompress4X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0); +} + + +#endif /* HUF_FORCE_DECOMPRESS_X2 */ + + +#ifndef HUF_FORCE_DECOMPRESS_X1 + +/* *************************/ +/* double-symbols decoding */ +/* *************************/ + +typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ +typedef struct { BYTE symbol; } sortedSymbol_t; +typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; +typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; + +/** + * Constructs a HUF_DEltX2 in a U32. + */ +static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + U32 seq; + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); + if (MEM_isLittleEndian()) { + seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); + return seq + (nbBits << 16) + ((U32)level << 24); + } else { + seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); + return (seq << 16) + (nbBits << 8) + (U32)level; + } +} + +/** + * Constructs a HUF_DEltX2. + */ +static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + HUF_DEltX2 DElt; + U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); + ZSTD_memcpy(&DElt, &val, sizeof(val)); + return DElt; +} + +/** + * Constructs 2 HUF_DEltX2s and packs them into a U64. + */ +static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) +{ + U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + return (U64)DElt + ((U64)DElt << 32); +} + +/** + * Fills the DTable rank with all the symbols from [begin, end) that are each + * nbBits long. + * + * @param DTableRank The start of the rank in the DTable. + * @param begin The first symbol to fill (inclusive). + * @param end The last symbol to fill (exclusive). + * @param nbBits Each symbol is nbBits long. + * @param tableLog The table log. + * @param baseSeq If level == 1 { 0 } else { the first level symbol } + * @param level The level in the table. Must be 1 or 2. + */ +static void HUF_fillDTableX2ForWeight( + HUF_DEltX2* DTableRank, + sortedSymbol_t const* begin, sortedSymbol_t const* end, + U32 nbBits, U32 tableLog, + U16 baseSeq, int const level) +{ + U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); + const sortedSymbol_t* ptr; + assert(level >= 1 && level <= 2); + switch (length) { + case 1: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + *DTableRank++ = DElt; + } + break; + case 2: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + DTableRank[0] = DElt; + DTableRank[1] = DElt; + DTableRank += 2; + } + break; + case 4: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + DTableRank += 4; + } + break; + case 8: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + DTableRank += 8; + } + break; + default: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + HUF_DEltX2* const DTableRankEnd = DTableRank + length; + for (; DTableRank != DTableRankEnd; DTableRank += 8) { + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + } + } + break; + } +} + +/* HUF_fillDTableX2Level2() : + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, + const U32* rankVal, const int minWeight, const int maxWeight1, + const sortedSymbol_t* sortedSymbols, U32 const* rankStart, + U32 nbBitsBaseline, U16 baseSeq) +{ + /* Fill skipped values (all positions up to rankVal[minWeight]). + * These are positions only get a single symbol because the combined weight + * is too large. + */ + if (minWeight>1) { + U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); + U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); + int const skipSize = rankVal[minWeight]; + assert(length > 1); + assert((U32)skipSize < length); + switch (length) { + case 2: + assert(skipSize == 1); + ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); + break; + case 4: + assert(skipSize <= 4); + ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); + break; + default: + { + int i; + for (i = 0; i < skipSize; i += 8) { + ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); + } + } + } + } + + /* Fill each of the second level symbols by weight. */ + { + int w; + for (w = minWeight; w < maxWeight1; ++w) { + int const begin = rankStart[w]; + int const end = rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + U32 const totalBits = nbBits + consumedBits; + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedSymbols + begin, sortedSymbols + end, + totalBits, targetLog, + baseSeq, /* level */ 2); + } + } +} + +static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, + const sortedSymbol_t* sortedList, + const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, + const U32 nbBitsBaseline) +{ + U32* const rankVal = rankValOrigin[0]; + const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ + const U32 minBits = nbBitsBaseline - maxWeight; + int w; + int const wEnd = (int)maxWeight + 1; + + /* Fill DTable in order of weight. */ + for (w = 1; w < wEnd; ++w) { + int const begin = (int)rankStart[w]; + int const end = (int)rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + + if (targetLog-nbBits >= minBits) { + /* Enough room for a second symbol. */ + int start = rankVal[w]; + U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); + int minWeight = nbBits + scaleLog; + int s; + if (minWeight < 1) minWeight = 1; + /* Fill the DTable for every symbol of weight w. + * These symbols get at least 1 second symbol. + */ + for (s = begin; s != end; ++s) { + HUF_fillDTableX2Level2( + DTable + start, targetLog, nbBits, + rankValOrigin[nbBits], minWeight, wEnd, + sortedList, rankStart, + nbBitsBaseline, sortedList[s].symbol); + start += length; + } + } else { + /* Only a single symbol. */ + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedList + begin, sortedList + end, + nbBits, targetLog, + /* baseSeq */ 0, /* level */ 1); + } + } +} + +typedef struct { + rankValCol_t rankVal[HUF_TABLELOG_MAX]; + U32 rankStats[HUF_TABLELOG_MAX + 1]; + U32 rankStart0[HUF_TABLELOG_MAX + 3]; + sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; + BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; + U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; +} HUF_ReadDTableX2_Workspace; + +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readDTableX2_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + U32 tableLog, maxW, nbSymbols; + DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 maxTableLog = dtd.maxTableLog; + size_t iSize; + void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ + HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; + U32 *rankStart; + + HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; + + if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); + + rankStart = wksp->rankStart0 + 1; + ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); + ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); + + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ + if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); + /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), bmi2); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ + if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; + + /* find maxWeight */ + for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + + /* Get start index of each weight */ + { U32 w, nextRankStart = 0; + for (w=1; wrankStats[w]; + rankStart[w] = curr; + } + rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ + rankStart[maxW+1] = nextRankStart; + } + + /* sort symbols by weight */ + { U32 s; + for (s=0; sweightList[s]; + U32 const r = rankStart[w]++; + wksp->sortedSymbol[r].symbol = (BYTE)s; + } + rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ + } + + /* Build rankVal */ + { U32* const rankVal0 = wksp->rankVal[0]; + { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ + U32 nextRankVal = 0; + U32 w; + for (w=1; wrankStats[w] << (w+rescale); + rankVal0[w] = curr; + } } + { U32 const minBits = tableLog+1 - maxW; + U32 consumed; + for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { + U32* const rankValPtr = wksp->rankVal[consumed]; + U32 w; + for (w = 1; w < maxW+1; w++) { + rankValPtr[w] = rankVal0[w] >> consumed; + } } } } + + HUF_fillDTableX2(dt, maxTableLog, + wksp->sortedSymbol, + wksp->rankStart0, wksp->rankVal, maxW, + tableLog+1); + + dtd.tableLog = (BYTE)maxTableLog; + dtd.tableType = 1; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + return iSize; +} + + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 2); + BIT_skipBits(DStream, dt[val].nbBits); + return dt[val].length; +} + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 1); + if (dt[val].length==1) { + BIT_skipBits(DStream, dt[val].nbBits); + } else { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { + BIT_skipBits(DStream, dt[val].nbBits); + if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) + /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); + } + } + return 1; +} + +#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +HINT_INLINE size_t +HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, + const HUF_DEltX2* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 8 symbols at a time */ + if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { + if (dtLog <= 11 && MEM_64bits()) { + /* up to 10 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } else { + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* closer to end : up to 2 symbols at a time */ + if ((size_t)(pEnd - p) >= 2) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + } + + if (p < pEnd) + p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); + + return p-pStart; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BIT_DStream_t bitD; + + /* Init */ + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + /* decode */ + { BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog); + } + + /* check */ + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; +} +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - (sizeof(size_t)-1); + const void* const dtPtr = DTable+1; + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + size_t const segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal = 1; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* 16-32 symbols per loop (4-8 symbols per stream) */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit); ) { +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; +#else + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY((U32) + (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); +#endif + } + } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS size_t +HUF_decompress4X2_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) { + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(&args); + + /* note : op4 already verified within main loop */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bitStreams one by one */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) + return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ + +static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X2_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} + +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) + +size_t HUF_decompress1X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} + + +size_t HUF_decompress4X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + + +#endif /* HUF_FORCE_DECOMPRESS_X1 */ + + +/* ***********************************/ +/* Universal decompression selectors */ +/* ***********************************/ + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + + +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) +typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; +static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = +{ + /* single, double, quad */ + {{0,0}, {1,1}}, /* Q==0 : impossible */ + {{0,0}, {1,1}}, /* Q==1 : impossible */ + {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ + {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ + {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ + {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ + {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ + {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ + {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ + {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ + {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ + {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ + {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ + {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ + {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ + {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ +}; +#endif + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) +{ + assert(dstSize > 0); + assert(dstSize <= 128*1024); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dstSize; + (void)cSrcSize; + return 0; +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dstSize; + (void)cSrcSize; + return 1; +#else + /* decoder timing evaluation */ + { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */ + U32 const D256 = (U32)(dstSize >> 8); + U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); + U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); + DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ + return DTime1 < DTime0; + } +#endif +} + + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, + size_t dstSize, const void* cSrc, + size_t cSrcSize, void* workSpace, + size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#endif + } +} + +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#endif + } +} + + +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#endif +} + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} +#endif + +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#endif +} + +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) : + HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#endif + } +} + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX1_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); + +size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) + static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; +#endif + + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); +#else + return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); +#endif + } +} + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#else + return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : + HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; +#endif + } +} + +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +#endif diff --git a/stage1/zstd/lib/decompress/huf_decompress_amd64.S b/stage1/zstd/lib/decompress/huf_decompress_amd64.S new file mode 100644 index 000000000000..49589cb61141 --- /dev/null +++ b/stage1/zstd/lib/decompress/huf_decompress_amd64.S @@ -0,0 +1,585 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#include "../common/portability_macros.h" + +/* Stack marking + * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart + */ +#if defined(__ELF__) && defined(__GNUC__) +.section .note.GNU-stack,"",%progbits +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +/* Calling convention: + * + * %rdi contains the first argument: HUF_DecompressAsmArgs*. + * %rbp isn't maintained (no frame pointer). + * %rsp contains the stack pointer that grows down. + * No red-zone is assumed, only addresses >= %rsp are used. + * All register contents are preserved. + * + * TODO: Support Windows calling convention. + */ + +ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) +ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) +.global HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop +.global HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop +.global _HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop +.global _HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop +.text + +/* Sets up register mappings for clarity. + * op[], bits[], dtable & ip[0] each get their own register. + * ip[1,2,3] & olimit alias var[]. + * %rax is a scratch register. + */ + +#define op0 rsi +#define op1 rbx +#define op2 rcx +#define op3 rdi + +#define ip0 r8 +#define ip1 r9 +#define ip2 r10 +#define ip3 r11 + +#define bits0 rbp +#define bits1 rdx +#define bits2 r12 +#define bits3 r13 +#define dtable r14 +#define olimit r15 + +/* var[] aliases ip[1,2,3] & olimit + * ip[1,2,3] are saved every iteration. + * olimit is only used in compute_olimit. + */ +#define var0 r15 +#define var1 r9 +#define var2 r10 +#define var3 r11 + +/* 32-bit var registers */ +#define vard0 r15d +#define vard1 r9d +#define vard2 r10d +#define vard3 r11d + +/* Calls X(N) for each stream 0, 1, 2, 3. */ +#define FOR_EACH_STREAM(X) \ + X(0); \ + X(1); \ + X(2); \ + X(3) + +/* Calls X(N, idx) for each stream 0, 1, 2, 3. */ +#define FOR_EACH_STREAM_WITH_INDEX(X, idx) \ + X(0, idx); \ + X(1, idx); \ + X(2, idx); \ + X(3, idx) + +/* Define both _HUF_* & HUF_* symbols because MacOS + * C symbols are prefixed with '_' & Linux symbols aren't. + */ +_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: +HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: + /* Save all registers - even if they are callee saved for simplicity. */ + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + /* Read HUF_DecompressAsmArgs* args from %rax */ + movq %rdi, %rax + movq 0(%rax), %ip0 + movq 8(%rax), %ip1 + movq 16(%rax), %ip2 + movq 24(%rax), %ip3 + movq 32(%rax), %op0 + movq 40(%rax), %op1 + movq 48(%rax), %op2 + movq 56(%rax), %op3 + movq 64(%rax), %bits0 + movq 72(%rax), %bits1 + movq 80(%rax), %bits2 + movq 88(%rax), %bits3 + movq 96(%rax), %dtable + push %rax /* argument */ + push 104(%rax) /* ilimit */ + push 112(%rax) /* oend */ + push %olimit /* olimit space */ + + subq $24, %rsp + +.L_4X1_compute_olimit: + /* Computes how many iterations we can do safely + * %r15, %rax may be clobbered + * rbx, rdx must be saved + * op3 & ip0 mustn't be clobbered + */ + movq %rbx, 0(%rsp) + movq %rdx, 8(%rsp) + + movq 32(%rsp), %rax /* rax = oend */ + subq %op3, %rax /* rax = oend - op3 */ + + /* r15 = (oend - op3) / 5 */ + movabsq $-3689348814741910323, %rdx + mulq %rdx + movq %rdx, %r15 + shrq $2, %r15 + + movq %ip0, %rax /* rax = ip0 */ + movq 40(%rsp), %rdx /* rdx = ilimit */ + subq %rdx, %rax /* rax = ip0 - ilimit */ + movq %rax, %rbx /* rbx = ip0 - ilimit */ + + /* rdx = (ip0 - ilimit) / 7 */ + movabsq $2635249153387078803, %rdx + mulq %rdx + subq %rdx, %rbx + shrq %rbx + addq %rbx, %rdx + shrq $2, %rdx + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + /* r15 = r15 * 5 */ + leaq (%r15, %r15, 4), %r15 + + /* olimit = op3 + r15 */ + addq %op3, %olimit + + movq 8(%rsp), %rdx + movq 0(%rsp), %rbx + + /* If (op3 + 20 > olimit) */ + movq %op3, %rax /* rax = op3 */ + addq $20, %rax /* rax = op3 + 20 */ + cmpq %rax, %olimit /* op3 + 20 > olimit */ + jb .L_4X1_exit + + /* If (ip1 < ip0) go to exit */ + cmpq %ip0, %ip1 + jb .L_4X1_exit + + /* If (ip2 < ip1) go to exit */ + cmpq %ip1, %ip2 + jb .L_4X1_exit + + /* If (ip3 < ip2) go to exit */ + cmpq %ip2, %ip3 + jb .L_4X1_exit + +/* Reads top 11 bits from bits[n] + * Loads dt[bits[n]] into var[n] + */ +#define GET_NEXT_DELT(n) \ + movq $53, %var##n; \ + shrxq %var##n, %bits##n, %var##n; \ + movzwl (%dtable,%var##n,2),%vard##n + +/* var[n] must contain the DTable entry computed with GET_NEXT_DELT + * Moves var[n] to %rax + * bits[n] <<= var[n] & 63 + * op[n][idx] = %rax >> 8 + * %ah is a way to access bits [8, 16) of %rax + */ +#define DECODE_FROM_DELT(n, idx) \ + movq %var##n, %rax; \ + shlxq %var##n, %bits##n, %bits##n; \ + movb %ah, idx(%op##n) + +/* Assumes GET_NEXT_DELT has been called. + * Calls DECODE_FROM_DELT then GET_NEXT_DELT + */ +#define DECODE_AND_GET_NEXT(n, idx) \ + DECODE_FROM_DELT(n, idx); \ + GET_NEXT_DELT(n) \ + +/* // ctz & nbBytes is stored in bits[n] + * // nbBits is stored in %rax + * ctz = CTZ[bits[n]] + * nbBits = ctz & 7 + * nbBytes = ctz >> 3 + * op[n] += 5 + * ip[n] -= nbBytes + * // Note: x86-64 is little-endian ==> no bswap + * bits[n] = MEM_readST(ip[n]) | 1 + * bits[n] <<= nbBits + */ +#define RELOAD_BITS(n) \ + bsfq %bits##n, %bits##n; \ + movq %bits##n, %rax; \ + andq $7, %rax; \ + shrq $3, %bits##n; \ + leaq 5(%op##n), %op##n; \ + subq %bits##n, %ip##n; \ + movq (%ip##n), %bits##n; \ + orq $1, %bits##n; \ + shlx %rax, %bits##n, %bits##n + + /* Store clobbered variables on the stack */ + movq %olimit, 24(%rsp) + movq %ip1, 0(%rsp) + movq %ip2, 8(%rsp) + movq %ip3, 16(%rsp) + + /* Call GET_NEXT_DELT for each stream */ + FOR_EACH_STREAM(GET_NEXT_DELT) + + .p2align 6 + +.L_4X1_loop_body: + /* Decode 5 symbols in each of the 4 streams (20 total) + * Must have called GET_NEXT_DELT for each stream + */ + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 0) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 1) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 2) + FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 3) + FOR_EACH_STREAM_WITH_INDEX(DECODE_FROM_DELT, 4) + + /* Load ip[1,2,3] from stack (var[] aliases them) + * ip[] is needed for RELOAD_BITS + * Each will be stored back to the stack after RELOAD + */ + movq 0(%rsp), %ip1 + movq 8(%rsp), %ip2 + movq 16(%rsp), %ip3 + + /* Reload each stream & fetch the next table entry + * to prepare for the next iteration + */ + RELOAD_BITS(0) + GET_NEXT_DELT(0) + + RELOAD_BITS(1) + movq %ip1, 0(%rsp) + GET_NEXT_DELT(1) + + RELOAD_BITS(2) + movq %ip2, 8(%rsp) + GET_NEXT_DELT(2) + + RELOAD_BITS(3) + movq %ip3, 16(%rsp) + GET_NEXT_DELT(3) + + /* If op3 < olimit: continue the loop */ + cmp %op3, 24(%rsp) + ja .L_4X1_loop_body + + /* Reload ip[1,2,3] from stack */ + movq 0(%rsp), %ip1 + movq 8(%rsp), %ip2 + movq 16(%rsp), %ip3 + + /* Re-compute olimit */ + jmp .L_4X1_compute_olimit + +#undef GET_NEXT_DELT +#undef DECODE_FROM_DELT +#undef DECODE +#undef RELOAD_BITS +.L_4X1_exit: + addq $24, %rsp + + /* Restore stack (oend & olimit) */ + pop %rax /* olimit */ + pop %rax /* oend */ + pop %rax /* ilimit */ + pop %rax /* arg */ + + /* Save ip / op / bits */ + movq %ip0, 0(%rax) + movq %ip1, 8(%rax) + movq %ip2, 16(%rax) + movq %ip3, 24(%rax) + movq %op0, 32(%rax) + movq %op1, 40(%rax) + movq %op2, 48(%rax) + movq %op3, 56(%rax) + movq %bits0, 64(%rax) + movq %bits1, 72(%rax) + movq %bits2, 80(%rax) + movq %bits3, 88(%rax) + + /* Restore registers */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + ret + +_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: +HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: + /* Save all registers - even if they are callee saved for simplicity. */ + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + movq %rdi, %rax + movq 0(%rax), %ip0 + movq 8(%rax), %ip1 + movq 16(%rax), %ip2 + movq 24(%rax), %ip3 + movq 32(%rax), %op0 + movq 40(%rax), %op1 + movq 48(%rax), %op2 + movq 56(%rax), %op3 + movq 64(%rax), %bits0 + movq 72(%rax), %bits1 + movq 80(%rax), %bits2 + movq 88(%rax), %bits3 + movq 96(%rax), %dtable + push %rax /* argument */ + push %rax /* olimit */ + push 104(%rax) /* ilimit */ + + movq 112(%rax), %rax + push %rax /* oend3 */ + + movq %op3, %rax + push %rax /* oend2 */ + + movq %op2, %rax + push %rax /* oend1 */ + + movq %op1, %rax + push %rax /* oend0 */ + + /* Scratch space */ + subq $8, %rsp + +.L_4X2_compute_olimit: + /* Computes how many iterations we can do safely + * %r15, %rax may be clobbered + * rdx must be saved + * op[1,2,3,4] & ip0 mustn't be clobbered + */ + movq %rdx, 0(%rsp) + + /* We can consume up to 7 input bytes each iteration. */ + movq %ip0, %rax /* rax = ip0 */ + movq 40(%rsp), %rdx /* rdx = ilimit */ + subq %rdx, %rax /* rax = ip0 - ilimit */ + movq %rax, %r15 /* r15 = ip0 - ilimit */ + + /* rdx = rax / 7 */ + movabsq $2635249153387078803, %rdx + mulq %rdx + subq %rdx, %r15 + shrq %r15 + addq %r15, %rdx + shrq $2, %rdx + + /* r15 = (ip0 - ilimit) / 7 */ + movq %rdx, %r15 + + movabsq $-3689348814741910323, %rdx + movq 8(%rsp), %rax /* rax = oend0 */ + subq %op0, %rax /* rax = oend0 - op0 */ + mulq %rdx + shrq $3, %rdx /* rdx = rax / 10 */ + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + movabsq $-3689348814741910323, %rdx + movq 16(%rsp), %rax /* rax = oend1 */ + subq %op1, %rax /* rax = oend1 - op1 */ + mulq %rdx + shrq $3, %rdx /* rdx = rax / 10 */ + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + movabsq $-3689348814741910323, %rdx + movq 24(%rsp), %rax /* rax = oend2 */ + subq %op2, %rax /* rax = oend2 - op2 */ + mulq %rdx + shrq $3, %rdx /* rdx = rax / 10 */ + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + movabsq $-3689348814741910323, %rdx + movq 32(%rsp), %rax /* rax = oend3 */ + subq %op3, %rax /* rax = oend3 - op3 */ + mulq %rdx + shrq $3, %rdx /* rdx = rax / 10 */ + + /* r15 = min(%rdx, %r15) */ + cmpq %rdx, %r15 + cmova %rdx, %r15 + + /* olimit = op3 + 5 * r15 */ + movq %r15, %rax + leaq (%op3, %rax, 4), %olimit + addq %rax, %olimit + + movq 0(%rsp), %rdx + + /* If (op3 + 10 > olimit) */ + movq %op3, %rax /* rax = op3 */ + addq $10, %rax /* rax = op3 + 10 */ + cmpq %rax, %olimit /* op3 + 10 > olimit */ + jb .L_4X2_exit + + /* If (ip1 < ip0) go to exit */ + cmpq %ip0, %ip1 + jb .L_4X2_exit + + /* If (ip2 < ip1) go to exit */ + cmpq %ip1, %ip2 + jb .L_4X2_exit + + /* If (ip3 < ip2) go to exit */ + cmpq %ip2, %ip3 + jb .L_4X2_exit + +#define DECODE(n, idx) \ + movq %bits##n, %rax; \ + shrq $53, %rax; \ + movzwl 0(%dtable,%rax,4),%r8d; \ + movzbl 2(%dtable,%rax,4),%r15d; \ + movzbl 3(%dtable,%rax,4),%eax; \ + movw %r8w, (%op##n); \ + shlxq %r15, %bits##n, %bits##n; \ + addq %rax, %op##n + +#define RELOAD_BITS(n) \ + bsfq %bits##n, %bits##n; \ + movq %bits##n, %rax; \ + shrq $3, %bits##n; \ + andq $7, %rax; \ + subq %bits##n, %ip##n; \ + movq (%ip##n), %bits##n; \ + orq $1, %bits##n; \ + shlxq %rax, %bits##n, %bits##n + + + movq %olimit, 48(%rsp) + + .p2align 6 + +.L_4X2_loop_body: + /* We clobber r8, so store it on the stack */ + movq %r8, 0(%rsp) + + /* Decode 5 symbols from each of the 4 streams (20 symbols total). */ + FOR_EACH_STREAM_WITH_INDEX(DECODE, 0) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 1) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 2) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 3) + FOR_EACH_STREAM_WITH_INDEX(DECODE, 4) + + /* Reload r8 */ + movq 0(%rsp), %r8 + + FOR_EACH_STREAM(RELOAD_BITS) + + cmp %op3, 48(%rsp) + ja .L_4X2_loop_body + jmp .L_4X2_compute_olimit + +#undef DECODE +#undef RELOAD_BITS +.L_4X2_exit: + addq $8, %rsp + /* Restore stack (oend & olimit) */ + pop %rax /* oend0 */ + pop %rax /* oend1 */ + pop %rax /* oend2 */ + pop %rax /* oend3 */ + pop %rax /* ilimit */ + pop %rax /* olimit */ + pop %rax /* arg */ + + /* Save ip / op / bits */ + movq %ip0, 0(%rax) + movq %ip1, 8(%rax) + movq %ip2, 16(%rax) + movq %ip3, 24(%rax) + movq %op0, 32(%rax) + movq %op1, 40(%rax) + movq %op2, 48(%rax) + movq %op3, 56(%rax) + movq %bits0, 64(%rax) + movq %bits1, 72(%rax) + movq %bits2, 80(%rax) + movq %bits3, 88(%rax) + + /* Restore registers */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + ret + +#endif diff --git a/stage1/zstd/lib/decompress/zstd_ddict.c b/stage1/zstd/lib/decompress/zstd_ddict.c new file mode 100644 index 000000000000..ce335477b32d --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_ddict.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_ddict.c : + * concentrates all logic that needs to know the internals of ZSTD_DDict object */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "zstd_decompress_internal.h" +#include "zstd_ddict.h" + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/*-******************************************************* +* Types +*********************************************************/ +struct ZSTD_DDict_s { + void* dictBuffer; + const void* dictContent; + size_t dictSize; + ZSTD_entropyDTables_t entropy; + U32 dictID; + U32 entropyPresent; + ZSTD_customMem cMem; +}; /* typedef'd to ZSTD_DDict within "zstd.h" */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictContent; +} + +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictSize; +} + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_copyDDictParameters"); + assert(dctx != NULL); + assert(ddict != NULL); + dctx->dictID = ddict->dictID; + dctx->prefixStart = ddict->dictContent; + dctx->virtualStart = ddict->dictContent; + dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; + dctx->previousDstEnd = dctx->dictEnd; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + if (ddict->entropyPresent) { + dctx->litEntropy = 1; + dctx->fseEntropy = 1; + dctx->LLTptr = ddict->entropy.LLTable; + dctx->MLTptr = ddict->entropy.MLTable; + dctx->OFTptr = ddict->entropy.OFTable; + dctx->HUFptr = ddict->entropy.hufTable; + dctx->entropy.rep[0] = ddict->entropy.rep[0]; + dctx->entropy.rep[1] = ddict->entropy.rep[1]; + dctx->entropy.rep[2] = ddict->entropy.rep[2]; + } else { + dctx->litEntropy = 0; + dctx->fseEntropy = 0; + } +} + + +static size_t +ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, + ZSTD_dictContentType_e dictContentType) +{ + ddict->dictID = 0; + ddict->entropyPresent = 0; + if (dictContentType == ZSTD_dct_rawContent) return 0; + + if (ddict->dictSize < 8) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + { U32 const magic = MEM_readLE32(ddict->dictContent); + if (magic != ZSTD_MAGIC_DICTIONARY) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + } + ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( + &ddict->entropy, ddict->dictContent, ddict->dictSize)), + dictionary_corrupted, ""); + ddict->entropyPresent = 1; + return 0; +} + + +static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) { + ddict->dictBuffer = NULL; + ddict->dictContent = dict; + if (!dict) dictSize = 0; + } else { + void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); + ddict->dictBuffer = internalBuffer; + ddict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + ZSTD_memcpy(internalBuffer, dict, dictSize); + } + ddict->dictSize = dictSize; + ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + + /* parse dictionary content */ + FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); + + return 0; +} + +ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem) +{ + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); + if (ddict == NULL) return NULL; + ddict->cMem = customMem; + { size_t const initResult = ZSTD_initDDict_internal(ddict, + dict, dictSize, + dictLoadMethod, dictContentType); + if (ZSTD_isError(initResult)) { + ZSTD_freeDDict(ddict); + return NULL; + } } + return ddict; + } +} + +/*! ZSTD_createDDict() : +* Create a digested dictionary, to start decompression without startup delay. +* `dict` content is copied inside DDict. +* Consequently, `dict` can be released after `ZSTD_DDict` creation */ +ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator); +} + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, to start decompression without startup delay. + * Dictionary content is simply referenced, it will be accessed during decompression. + * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */ +ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator); +} + + +const ZSTD_DDict* ZSTD_initStaticDDict( + void* sBuffer, size_t sBufferSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + size_t const neededSpace = sizeof(ZSTD_DDict) + + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); + ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer; + assert(sBuffer != NULL); + assert(dict != NULL); + if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ + if (sBufferSize < neededSpace) return NULL; + if (dictLoadMethod == ZSTD_dlm_byCopy) { + ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ + dict = ddict+1; + } + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, + dict, dictSize, + ZSTD_dlm_byRef, dictContentType) )) + return NULL; + return ddict; +} + + +size_t ZSTD_freeDDict(ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support free on NULL */ + { ZSTD_customMem const cMem = ddict->cMem; + ZSTD_customFree(ddict->dictBuffer, cMem); + ZSTD_customFree(ddict, cMem); + return 0; + } +} + +/*! ZSTD_estimateDDictSize() : + * Estimate amount of memory that will be needed to create a dictionary for decompression. + * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */ +size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) +{ + return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); +} + +size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support sizeof on NULL */ + return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ; +} + +/*! ZSTD_getDictID_fromDDict() : + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; + return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize); +} diff --git a/stage1/zstd/lib/decompress/zstd_ddict.h b/stage1/zstd/lib/decompress/zstd_ddict.h new file mode 100644 index 000000000000..bd03268b5087 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_ddict.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DDICT_H +#define ZSTD_DDICT_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* ZSTD_DDict, and several public functions */ + + +/*-******************************************************* + * Interface + *********************************************************/ + +/* note: several prototypes are already published in `zstd.h` : + * ZSTD_createDDict() + * ZSTD_createDDict_byReference() + * ZSTD_createDDict_advanced() + * ZSTD_freeDDict() + * ZSTD_initStaticDDict() + * ZSTD_sizeof_DDict() + * ZSTD_estimateDDictSize() + * ZSTD_getDictID_fromDict() + */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict); +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + + + +#endif /* ZSTD_DDICT_H */ diff --git a/stage1/zstd/lib/decompress/zstd_decompress.c b/stage1/zstd/lib/decompress/zstd_decompress.c new file mode 100644 index 000000000000..0031e98cfb1a --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress.c @@ -0,0 +1,2230 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* *************************************************************** +* Tuning parameters +*****************************************************************/ +/*! + * HEAPMODE : + * Select how default decompression function ZSTD_decompress() allocates its context, + * on stack (0), or into heap (1, default; requires malloc()). + * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected. + */ +#ifndef ZSTD_HEAPMODE +# define ZSTD_HEAPMODE 1 +#endif + +/*! +* LEGACY_SUPPORT : +* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+) +*/ +#ifndef ZSTD_LEGACY_SUPPORT +# define ZSTD_LEGACY_SUPPORT 0 +#endif + +/*! + * MAXWINDOWSIZE_DEFAULT : + * maximum window size accepted by DStream __by default__. + * Frames requiring more memory will be rejected. + * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize(). + */ +#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT +# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) +#endif + +/*! + * NO_FORWARD_PROGRESS_MAX : + * maximum allowed nb of calls to ZSTD_decompressStream() + * without any forward progress + * (defined as: no byte read from input, and no byte flushed to output) + * before triggering an error. + */ +#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX +# define ZSTD_NO_FORWARD_PROGRESS_MAX 16 +#endif + + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "../common/zstd_internal.h" /* blockProperties_t */ +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/************************************* + * Multiple DDicts Hashset internals * + *************************************/ + +#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 +#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. + * Currently, that means a 0.75 load factor. + * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded + * the load factor of the ddict hash set. + */ + +#define DDICT_HASHSET_TABLE_BASE_SIZE 64 +#define DDICT_HASHSET_RESIZE_FACTOR 2 + +/* Hash function to determine starting position of dict insertion within the table + * Returns an index between [0, hashSet->ddictPtrTableSize] + */ +static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { + const U64 hash = XXH64(&dictID, sizeof(U32), 0); + /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ + return hash & (hashSet->ddictPtrTableSize - 1); +} + +/* Adds DDict to a hashset without resizing it. + * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. + * Returns 0 if successful, or a zstd error code if something went wrong. + */ +static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { + const U32 dictID = ZSTD_getDictID_fromDDict(ddict); + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + while (hashSet->ddictPtrTable[idx] != NULL) { + /* Replace existing ddict if inserting ddict with same dictID */ + if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { + DEBUGLOG(4, "DictID already exists, replacing rather than adding"); + hashSet->ddictPtrTable[idx] = ddict; + return 0; + } + idx &= idxRangeMask; + idx++; + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + hashSet->ddictPtrTable[idx] = ddict; + hashSet->ddictPtrCount++; + return 0; +} + +/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and + * rehashes all values, allocates new table, frees old table. + * Returns 0 on success, otherwise a zstd error code. + */ +static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; + const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); + const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; + size_t oldTableSize = hashSet->ddictPtrTableSize; + size_t i; + + DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); + RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); + hashSet->ddictPtrTable = newTable; + hashSet->ddictPtrTableSize = newTableSize; + hashSet->ddictPtrCount = 0; + for (i = 0; i < oldTableSize; ++i) { + if (oldTable[i] != NULL) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); + } + } + ZSTD_customFree((void*)oldTable, customMem); + DEBUGLOG(4, "Finished re-hash"); + return 0; +} + +/* Fetches a DDict with the given dictID + * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. + */ +static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + for (;;) { + size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); + if (currDictID == dictID || currDictID == 0) { + /* currDictID == 0 implies a NULL ddict entry */ + break; + } else { + idx &= idxRangeMask; /* Goes to start of table when we reach the end */ + idx++; + } + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + return hashSet->ddictPtrTable[idx]; +} + +/* Allocates space for and returns a ddict hash set + * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. + * Returns NULL if allocation failed. + */ +static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { + ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); + DEBUGLOG(4, "Allocating new hash set"); + if (!ret) + return NULL; + ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); + if (!ret->ddictPtrTable) { + ZSTD_customFree(ret, customMem); + return NULL; + } + ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; + ret->ddictPtrCount = 0; + return ret; +} + +/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. + * Note: The ZSTD_DDict* within the table are NOT freed. + */ +static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + DEBUGLOG(4, "Freeing ddict hash set"); + if (hashSet && hashSet->ddictPtrTable) { + ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); + } + if (hashSet) { + ZSTD_customFree(hashSet, customMem); + } +} + +/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. + * Returns 0 on success, or a ZSTD error. + */ +static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { + DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); + if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); + } + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); + return 0; +} + +/*-************************************************************* +* Context management +***************************************************************/ +size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support sizeof NULL */ + return sizeof(*dctx) + + ZSTD_sizeof_DDict(dctx->ddictLocal) + + dctx->inBuffSize + dctx->outBuffSize; +} + +size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } + + +static size_t ZSTD_startingInputLength(ZSTD_format_e format) +{ + size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format); + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); + return startingInputLength; +} + +static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) +{ + assert(dctx->streamStage == zdss_init); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->outBufferMode = ZSTD_bm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; +} + +static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) +{ + dctx->staticSize = 0; + dctx->ddict = NULL; + dctx->ddictLocal = NULL; + dctx->dictEnd = NULL; + dctx->ddictIsCold = 0; + dctx->dictUses = ZSTD_dont_use; + dctx->inBuff = NULL; + dctx->inBuffSize = 0; + dctx->outBuffSize = 0; + dctx->streamStage = zdss_init; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + dctx->legacyContext = NULL; + dctx->previousLegacyVersion = 0; +#endif + dctx->noForwardProgress = 0; + dctx->oversizedDuration = 0; +#if DYNAMIC_BMI2 + dctx->bmi2 = ZSTD_cpuSupportsBmi2(); +#endif + dctx->ddictSet = NULL; + ZSTD_DCtx_resetParameters(dctx); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentEndForFuzzing = NULL; +#endif +} + +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace; + + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ + + ZSTD_initDCtx_internal(dctx); + dctx->staticSize = workspaceSize; + dctx->inBuff = (char*)(dctx+1); + return dctx; +} + +static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); + if (!dctx) return NULL; + dctx->customMem = customMem; + ZSTD_initDCtx_internal(dctx); + return dctx; + } +} + +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +ZSTD_DCtx* ZSTD_createDCtx(void) +{ + DEBUGLOG(3, "ZSTD_createDCtx"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +static void ZSTD_clearDict(ZSTD_DCtx* dctx) +{ + ZSTD_freeDDict(dctx->ddictLocal); + dctx->ddictLocal = NULL; + dctx->ddict = NULL; + dctx->dictUses = ZSTD_dont_use; +} + +size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support free on NULL */ + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); + { ZSTD_customMem const cMem = dctx->customMem; + ZSTD_clearDict(dctx); + ZSTD_customFree(dctx->inBuff, cMem); + dctx->inBuff = NULL; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (dctx->legacyContext) + ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); +#endif + if (dctx->ddictSet) { + ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); + dctx->ddictSet = NULL; + } + ZSTD_customFree(dctx, cMem); + return 0; + } +} + +/* no longer useful */ +void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +{ + size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); + ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ +} + +/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on + * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then + * accordingly sets the ddict to be used to decompress the frame. + * + * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. + * + * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. + */ +static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { + assert(dctx->refMultipleDDicts && dctx->ddictSet); + DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); + if (dctx->ddict) { + const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); + if (frameDDict) { + DEBUGLOG(4, "DDict found!"); + ZSTD_clearDict(dctx); + dctx->dictID = dctx->fParams.dictID; + dctx->ddict = frameDDict; + dctx->dictUses = ZSTD_use_indefinitely; + } + } +} + + +/*-************************************************************* + * Frame header decoding + ***************************************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +unsigned ZSTD_isFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if (magic == ZSTD_MAGICNUMBER) return 1; + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(buffer, size)) return 1; +#endif + return 0; +} + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + */ +unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } + return 0; +} + +/** ZSTD_frameHeaderSize_internal() : + * srcSize must be large enough to reach header size fields. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. + * @return : size of the Frame Header + * or an error code, which can be tested with ZSTD_isError() */ +static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) +{ + size_t const minInputSize = ZSTD_startingInputLength(format); + RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, ""); + + { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; + U32 const dictID= fhd & 3; + U32 const singleSegment = (fhd >> 5) & 1; + U32 const fcsId = fhd >> 6; + return minInputSize + !singleSegment + + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + + (singleSegment && !fcsId); + } +} + +/** ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_frameHeaderSize_prefix. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) +{ + return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1); +} + + +/** ZSTD_getFrameHeader_advanced() : + * decode Frame Header, or require larger `srcSize`. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) +{ + const BYTE* ip = (const BYTE*)src; + size_t const minInputSize = ZSTD_startingInputLength(format); + + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ + if (srcSize < minInputSize) return minInputSize; + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); + + if ( (format != ZSTD_f_zstd1_magicless) + && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + /* skippable frame */ + if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) + return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); + zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); + zfhPtr->frameType = ZSTD_skippableFrame; + return 0; + } + RETURN_ERROR(prefix_unknown, ""); + } + + /* ensure there is enough `srcSize` to fully read/decode frame header */ + { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format); + if (srcSize < fhsize) return fhsize; + zfhPtr->headerSize = (U32)fhsize; + } + + { BYTE const fhdByte = ip[minInputSize-1]; + size_t pos = minInputSize; + U32 const dictIDSizeCode = fhdByte&3; + U32 const checksumFlag = (fhdByte>>2)&1; + U32 const singleSegment = (fhdByte>>5)&1; + U32 const fcsID = fhdByte>>6; + U64 windowSize = 0; + U32 dictID = 0; + U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN; + RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported, + "reserved bits, must be zero"); + + if (!singleSegment) { + BYTE const wlByte = ip[pos++]; + U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, ""); + windowSize = (1ULL << windowLog); + windowSize += (windowSize >> 3) * (wlByte&7); + } + switch(dictIDSizeCode) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : break; + case 1 : dictID = ip[pos]; pos++; break; + case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; + case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break; + } + switch(fcsID) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : if (singleSegment) frameContentSize = ip[pos]; break; + case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; + case 2 : frameContentSize = MEM_readLE32(ip+pos); break; + case 3 : frameContentSize = MEM_readLE64(ip+pos); break; + } + if (singleSegment) windowSize = frameContentSize; + + zfhPtr->frameType = ZSTD_frame; + zfhPtr->frameContentSize = frameContentSize; + zfhPtr->windowSize = windowSize; + zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + zfhPtr->dictID = dictID; + zfhPtr->checksumFlag = checksumFlag; + } + return 0; +} + +/** ZSTD_getFrameHeader() : + * decode Frame Header, or require larger `srcSize`. + * note : this function does not consume input, it only reads it. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize) +{ + return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); +} + +/** ZSTD_getFrameContentSize() : + * compatible with legacy mode + * @return : decompressed size of the single frame pointed to be `src` if known, otherwise + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */ +unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) +{ +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize); + return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret; + } +#endif + { ZSTD_frameHeader zfh; + if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0) + return ZSTD_CONTENTSIZE_ERROR; + if (zfh.frameType == ZSTD_skippableFrame) { + return 0; + } else { + return zfh.frameContentSize; + } } +} + +static size_t readSkippableFrameSize(void const* src, size_t srcSize) +{ + size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE; + U32 sizeU32; + + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + + sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); + RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, + frameParameter_unsupported, ""); + { + size_t const skippableSize = skippableHeaderSize + sizeU32; + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); + return skippableSize; + } +} + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize) +{ + U32 const magicNumber = MEM_readLE32(src); + size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); + size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; + + /* check input validity */ + RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); + RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); + + /* deliver payload */ + if (skippableContentSize > 0 && dst != NULL) + ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); + if (magicVariant != NULL) + *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; + return skippableContentSize; +} + +/** ZSTD_findDecompressedSize() : + * compatible with legacy mode + * `srcSize` must be the exact length of some number of ZSTD compressed and/or + * skippable frames + * @return : decompressed size of the frames contained */ +unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long totalDstSize = 0; + + while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) { + U32 const magicNumber = MEM_readLE32(src); + + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + if (ZSTD_isError(skippableSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } + + { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; + + /* check for overflow */ + if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; + totalDstSize += ret; + } + { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); + if (ZSTD_isError(frameSrcSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } + + src = (const BYTE *)src + frameSrcSize; + srcSize -= frameSrcSize; + } + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + if (srcSize) return ZSTD_CONTENTSIZE_ERROR; + + return totalDstSize; +} + +/** ZSTD_getDecompressedSize() : + * compatible with legacy mode + * @return : decompressed size if known, 0 otherwise + note : 0 can mean any of the following : + - frame content is empty + - decompressed size field is not present in frame header + - frame header unknown / not supported + - frame header not complete (`srcSize` too small) */ +unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN); + return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret; +} + + +/** ZSTD_decodeFrameHeader() : + * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). + * If multiple DDict references are enabled, also will choose the correct DDict to use. + * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ +static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) +{ + size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); + if (ZSTD_isError(result)) return result; /* invalid header */ + RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); + + /* Reference DDict requested by frame if dctx references multiple ddicts */ + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { + ZSTD_DCtx_selectFrameDDict(dctx); + } + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Skip the dictID check in fuzzing mode, because it makes the search + * harder. + */ + RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), + dictionary_wrong, ""); +#endif + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->processedCSize += headerSize; + return 0; +} + +static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) +{ + ZSTD_frameSizeInfo frameSizeInfo; + frameSizeInfo.compressedSize = ret; + frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR; + return frameSizeInfo; +} + +static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) +{ + ZSTD_frameSizeInfo frameSizeInfo; + ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) + return ZSTD_findFrameSizeInfoLegacy(src, srcSize); +#endif + + if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) + && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); + assert(ZSTD_isError(frameSizeInfo.compressedSize) || + frameSizeInfo.compressedSize <= srcSize); + return frameSizeInfo; + } else { + const BYTE* ip = (const BYTE*)src; + const BYTE* const ipstart = ip; + size_t remainingSize = srcSize; + size_t nbBlocks = 0; + ZSTD_frameHeader zfh; + + /* Extract Frame Header */ + { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(ret)) + return ZSTD_errorFrameSizeInfo(ret); + if (ret > 0) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + } + + ip += zfh.headerSize; + remainingSize -= zfh.headerSize; + + /* Iterate over each block */ + while (1) { + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) + return ZSTD_errorFrameSizeInfo(cBlockSize); + + if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + + ip += ZSTD_blockHeaderSize + cBlockSize; + remainingSize -= ZSTD_blockHeaderSize + cBlockSize; + nbBlocks++; + + if (blockProperties.lastBlock) break; + } + + /* Final frame content checksum */ + if (zfh.checksumFlag) { + if (remainingSize < 4) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + ip += 4; + } + + frameSizeInfo.compressedSize = (size_t)(ip - ipstart); + frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) + ? zfh.frameContentSize + : nbBlocks * zfh.blockSizeMax; + return frameSizeInfo; + } +} + +/** ZSTD_findFrameCompressedSize() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame + * `srcSize` must be at least as large as the frame contained + * @return : the compressed size of the frame starting at `src` */ +size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) +{ + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + return frameSizeInfo.compressedSize; +} + +/** ZSTD_decompressBound() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame or a skippeable frame + * `srcSize` must be at least as large as the frame contained + * @return : the maximum decompressed size of the compressed source + */ +unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) +{ + unsigned long long bound = 0; + /* Iterate over each frame */ + while (srcSize > 0) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + size_t const compressedSize = frameSizeInfo.compressedSize; + unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; + if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) + return ZSTD_CONTENTSIZE_ERROR; + assert(srcSize >= compressedSize); + src = (const BYTE*)src + compressedSize; + srcSize -= compressedSize; + bound += decompressedBound; + } + return bound; +} + + +/*-************************************************************* + * Frame decoding + ***************************************************************/ + +/** ZSTD_insertBlock() : + * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ +size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) +{ + DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); + ZSTD_checkContinuity(dctx, blockStart, blockSize); + dctx->previousDstEnd = (const char*)blockStart + blockSize; + return blockSize; +} + + +static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_copyRawBlock"); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (srcSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memcpy(dst, src, srcSize); + return srcSize; +} + +static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, + BYTE b, + size_t regenSize) +{ + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (regenSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memset(dst, b, regenSize); + return regenSize; +} + +static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) +{ +#if ZSTD_TRACE + if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + if (dctx->ddict) { + trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); + trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); + trace.dictionaryIsCold = dctx->ddictIsCold; + } + trace.uncompressedSize = (size_t)uncompressedSize; + trace.compressedSize = (size_t)compressedSize; + trace.dctx = dctx; + ZSTD_trace_decompress_end(dctx->traceCtx, &trace); + } +#else + (void)dctx; + (void)uncompressedSize; + (void)compressedSize; + (void)streaming; +#endif +} + + +/*! ZSTD_decompressFrame() : + * @dctx must be properly initialized + * will update *srcPtr and *srcSizePtr, + * to make *srcPtr progress by one frame. */ +static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void** srcPtr, size_t *srcSizePtr) +{ + const BYTE* const istart = (const BYTE*)(*srcPtr); + const BYTE* ip = istart; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; + BYTE* op = ostart; + size_t remainingSrcSize = *srcSizePtr; + + DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr); + + /* check */ + RETURN_ERROR_IF( + remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + + /* Frame Header */ + { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( + ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); + if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; + RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); + ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; + } + + /* Loop on each block */ + while (1) { + size_t decodedSize; + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + + ip += ZSTD_blockHeaderSize; + remainingSrcSize -= ZSTD_blockHeaderSize; + RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); + + switch(blockProperties.blockType) + { + case bt_compressed: + decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1, not_streaming); + break; + case bt_raw : + decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); + break; + case bt_rle : + decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize); + break; + case bt_reserved : + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + + if (ZSTD_isError(decodedSize)) return decodedSize; + if (dctx->validateChecksum) + XXH64_update(&dctx->xxhState, op, decodedSize); + if (decodedSize != 0) + op += decodedSize; + assert(ip != NULL); + ip += cBlockSize; + remainingSrcSize -= cBlockSize; + if (blockProperties.lastBlock) break; + } + + if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { + RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, + corruption_detected, ""); + } + if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } + ip += 4; + remainingSrcSize -= 4; + } + ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); + /* Allow caller to get size read */ + *srcPtr = ip; + *srcSizePtr = remainingSrcSize; + return (size_t)(op-ostart); +} + +static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + const ZSTD_DDict* ddict) +{ + void* const dststart = dst; + int moreThan1Frame = 0; + + DEBUGLOG(5, "ZSTD_decompressMultiFrame"); + assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */ + + if (ddict) { + dict = ZSTD_DDict_dictContent(ddict); + dictSize = ZSTD_DDict_dictSize(ddict); + } + + while (srcSize >= ZSTD_startingInputLength(dctx->format)) { + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + size_t decodedSize; + size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); + if (ZSTD_isError(frameSize)) return frameSize; + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, + "legacy support is not compatible with static dctx"); + + decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); + if (ZSTD_isError(decodedSize)) return decodedSize; + + assert(decodedSize <= dstCapacity); + dst = (BYTE*)dst + decodedSize; + dstCapacity -= decodedSize; + + src = (const BYTE*)src + frameSize; + srcSize -= frameSize; + + continue; + } +#endif + + { U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(4, "reading magic number %08X (expecting %08X)", + (unsigned)magicNumber, ZSTD_MAGICNUMBER); + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed"); + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } } + + if (ddict) { + /* we were called from ZSTD_decompress_usingDDict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), ""); + } else { + /* this will initialize correctly with no dict if dict == NULL, so + * use this in all cases but ddict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); + } + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, + &src, &srcSize); + RETURN_ERROR_IF( + (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) + && (moreThan1Frame==1), + srcSize_wrong, + "At least one frame successfully completed, " + "but following bytes are garbage: " + "it's more likely to be a srcSize error, " + "specifying more input bytes than size of frame(s). " + "Note: one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic bytes. " + "But this is _much_ less likely than a srcSize field error."); + if (ZSTD_isError(res)) return res; + assert(res <= dstCapacity); + if (res != 0) + dst = (BYTE*)dst + res; + dstCapacity -= res; + } + moreThan1Frame = 1; + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); + + return (size_t)((BYTE*)dst - (BYTE*)dststart); +} + +size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize) +{ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL); +} + + +static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) +{ + switch (dctx->dictUses) { + default: + assert(0 /* Impossible */); + ZSTD_FALLTHROUGH; + case ZSTD_dont_use: + ZSTD_clearDict(dctx); + return NULL; + case ZSTD_use_indefinitely: + return dctx->ddict; + case ZSTD_use_once: + dctx->dictUses = ZSTD_dont_use; + return dctx->ddict; + } +} + +size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx)); +} + + +size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ +#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) + size_t regenSize; + ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); + RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); + regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); + ZSTD_freeDCtx(dctx); + return regenSize; +#else /* stack mode */ + ZSTD_DCtx dctx; + ZSTD_initDCtx_internal(&dctx); + return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize); +#endif +} + + +/*-************************************** +* Advanced Streaming Decompression API +* Bufferless and synchronous +****************************************/ +size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } + +/** + * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed, + * we allow taking a partial block as the input. Currently only raw uncompressed blocks can + * be streamed. + * + * For blocks that can be streamed, this allows us to reduce the latency until we produce + * output, and avoid copying the input. + * + * @param inputSize - The total amount of input that the caller currently has. + */ +static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) { + if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock)) + return dctx->expected; + if (dctx->bType != bt_raw) + return dctx->expected; + return BOUNDED(1, inputSize, dctx->expected); +} + +ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { + switch(dctx->stage) + { + default: /* should not happen */ + assert(0); + ZSTD_FALLTHROUGH; + case ZSTDds_getFrameHeaderSize: + ZSTD_FALLTHROUGH; + case ZSTDds_decodeFrameHeader: + return ZSTDnit_frameHeader; + case ZSTDds_decodeBlockHeader: + return ZSTDnit_blockHeader; + case ZSTDds_decompressBlock: + return ZSTDnit_block; + case ZSTDds_decompressLastBlock: + return ZSTDnit_lastBlock; + case ZSTDds_checkChecksum: + return ZSTDnit_checksum; + case ZSTDds_decodeSkippableHeader: + ZSTD_FALLTHROUGH; + case ZSTDds_skipFrame: + return ZSTDnit_skippableFrame; + } +} + +static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } + +/** ZSTD_decompressContinue() : + * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress()) + * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); + /* Sanity check */ + RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + dctx->processedCSize += srcSize; + + switch (dctx->stage) + { + case ZSTDds_getFrameHeaderSize : + assert(src != NULL); + if (dctx->format == ZSTD_f_zstd1) { /* allows header */ + assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ + dctx->stage = ZSTDds_decodeSkippableHeader; + return 0; + } } + dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); + if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = dctx->headerSize - srcSize; + dctx->stage = ZSTDds_decodeFrameHeader; + return 0; + + case ZSTDds_decodeFrameHeader: + assert(src != NULL); + ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); + dctx->expected = ZSTD_blockHeaderSize; + dctx->stage = ZSTDds_decodeBlockHeader; + return 0; + + case ZSTDds_decodeBlockHeader: + { blockProperties_t bp; + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum"); + dctx->expected = cBlockSize; + dctx->bType = bp.blockType; + dctx->rleSize = bp.origSize; + if (cBlockSize) { + dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock; + return 0; + } + /* empty block */ + if (bp.lastBlock) { + if (dctx->fParams.checksumFlag) { + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + dctx->expected = 0; /* end of frame */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ + dctx->stage = ZSTDds_decodeBlockHeader; + } + return 0; + } + + case ZSTDds_decompressLastBlock: + case ZSTDds_decompressBlock: + DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock"); + { size_t rSize; + switch(dctx->bType) + { + case bt_compressed: + DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_raw : + assert(srcSize <= dctx->expected); + rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); + FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed"); + assert(rSize == srcSize); + dctx->expected -= rSize; + break; + case bt_rle : + rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_reserved : /* should never happen */ + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + FORWARD_IF_ERROR(rSize, ""); + RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); + DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); + dctx->decodedSize += rSize; + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + dctx->previousDstEnd = (char*)dst + rSize; + + /* Stay on the same stage until we are finished streaming the block. */ + if (dctx->expected > 0) { + return rSize; + } + + if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ + DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize); + RETURN_ERROR_IF( + dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && dctx->decodedSize != dctx->fParams.frameContentSize, + corruption_detected, ""); + if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; /* ends here */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->stage = ZSTDds_decodeBlockHeader; + dctx->expected = ZSTD_blockHeaderSize; + } + return rSize; + } + + case ZSTDds_checkChecksum: + assert(srcSize == 4); /* guaranteed by dctx->expected */ + { + if (dctx->validateChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + } + + case ZSTDds_decodeSkippableHeader: + assert(src != NULL); + assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); + ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ + dctx->stage = ZSTDds_skipFrame; + return 0; + + case ZSTDds_skipFrame: + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + } +} + + +static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dict; + dctx->previousDstEnd = (const char*)dict + dictSize; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + return 0; +} + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of entropy tables read */ +size_t +ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize) +{ + const BYTE* dictPtr = (const BYTE*)dict; + const BYTE* const dictEnd = dictPtr + dictSize; + + RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small"); + assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */ + dictPtr += 8; /* skip header = magic + dictID */ + + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable)); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable)); + ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE); + { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */ + size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable); +#ifdef HUF_FORCE_DECOMPRESS_X1 + /* in minimal huffman, we always use X1 variants */ + size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, + dictPtr, dictEnd - dictPtr, + workspace, workspaceSize); +#else + size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, + dictPtr, (size_t)(dictEnd - dictPtr), + workspace, workspaceSize); +#endif + RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); + dictPtr += hSize; + } + + { short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff, offcodeLog; + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->OFTable, + offcodeNCount, offcodeMaxValue, + OF_base, OF_bits, + offcodeLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */0); + dictPtr += offcodeHeaderSize; + } + + { short matchlengthNCount[MaxML+1]; + unsigned matchlengthMaxValue = MaxML, matchlengthLog; + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->MLTable, + matchlengthNCount, matchlengthMaxValue, + ML_base, ML_bits, + matchlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += matchlengthHeaderSize; + } + + { short litlengthNCount[MaxLL+1]; + unsigned litlengthMaxValue = MaxLL, litlengthLog; + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->LLTable, + litlengthNCount, litlengthMaxValue, + LL_base, LL_bits, + litlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += litlengthHeaderSize; + } + + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); + { int i; + size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12)); + for (i=0; i<3; i++) { + U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4; + RETURN_ERROR_IF(rep==0 || rep > dictContentSize, + dictionary_corrupted, ""); + entropy->rep[i] = rep; + } } + + return (size_t)(dictPtr - (const BYTE*)dict); +} + +static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize); + { U32 const magic = MEM_readLE32(dict); + if (magic != ZSTD_MAGIC_DICTIONARY) { + return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */ + } } + dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize); + RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, ""); + dict = (const char*)dict + eSize; + dictSize -= eSize; + } + dctx->litEntropy = dctx->fseEntropy = 1; + + /* reference dictionary content */ + return ZSTD_refDictContent(dctx, dict, dictSize); +} + +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) +{ + assert(dctx != NULL); +#if ZSTD_TRACE + dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; +#endif + dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ + dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->processedCSize = 0; + dctx->decodedSize = 0; + dctx->previousDstEnd = NULL; + dctx->prefixStart = NULL; + dctx->virtualStart = NULL; + dctx->dictEnd = NULL; + dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->litEntropy = dctx->fseEntropy = 0; + dctx->dictID = 0; + dctx->bType = bt_reserved; + ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); + ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + dctx->LLTptr = dctx->entropy.LLTable; + dctx->MLTptr = dctx->entropy.MLTable; + dctx->OFTptr = dctx->entropy.OFTable; + dctx->HUFptr = dctx->entropy.hufTable; + return 0; +} + +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (dict && dictSize) + RETURN_ERROR_IF( + ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)), + dictionary_corrupted, ""); + return 0; +} + + +/* ====== ZSTD_DDict ====== */ + +size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict"); + assert(dctx != NULL); + if (ddict) { + const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict); + size_t const dictSize = ZSTD_DDict_dictSize(ddict); + const void* const dictEnd = dictStart + dictSize; + dctx->ddictIsCold = (dctx->dictEnd != dictEnd); + DEBUGLOG(4, "DDict is %s", + dctx->ddictIsCold ? "~cold~" : "hot!"); + } + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (ddict) { /* NULL ddict is equivalent to no dictionary */ + ZSTD_copyDDictParameters(dctx, ddict); + } + return 0; +} + +/*! ZSTD_getDictID_fromDict() : + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) +{ + if (dictSize < 8) return 0; + if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0; + return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); +} + +/*! ZSTD_getDictID_fromFrame() : + * Provides the dictID required to decompress frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary (most common case). + * - The frame was built with dictID intentionally removed. + * Needed dictionary is a hidden information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, frame header could not be decoded. + * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use + * ZSTD_getFrameHeader(), which will provide a more precise error code. */ +unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) +{ + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; + size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); + if (ZSTD_isError(hError)) return 0; + return zfp.dictID; +} + + +/*! ZSTD_decompress_usingDDict() : +* Decompression using a pre-digested Dictionary +* Use dictionary without significant overhead. */ +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict) +{ + /* pass content and size in case legacy frames are encountered */ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, + NULL, 0, + ddict); +} + + +/*===================================== +* Streaming decompression +*====================================*/ + +ZSTD_DStream* ZSTD_createDStream(void) +{ + DEBUGLOG(3, "ZSTD_createDStream"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) +{ + return ZSTD_initStaticDCtx(workspace, workspaceSize); +} + +ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +size_t ZSTD_freeDStream(ZSTD_DStream* zds) +{ + return ZSTD_freeDCtx(zds); +} + + +/* *** Initialization *** */ + +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } + +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (dict && dictSize != 0) { + dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem); + RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!"); + dctx->ddict = dctx->ddictLocal; + dctx->dictUses = ZSTD_use_indefinitely; + } + return 0; +} + +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) +{ + FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), ""); + dctx->dictUses = ZSTD_use_once; + return 0; +} + +size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize) +{ + return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent); +} + + +/* ZSTD_initDStream_usingDict() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) +{ + DEBUGLOG(4, "ZSTD_initDStream_usingDict"); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , ""); + return ZSTD_startingInputLength(zds->format); +} + +/* note : this variant can't fail */ +size_t ZSTD_initDStream(ZSTD_DStream* zds) +{ + DEBUGLOG(4, "ZSTD_initDStream"); + return ZSTD_initDStream_usingDDict(zds, NULL); +} + +/* ZSTD_initDStream_usingDDict() : + * ddict will just be referenced, and must outlive decompression session + * this function cannot fail */ +size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) +{ + FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); + return ZSTD_startingInputLength(dctx->format); +} + +/* ZSTD_resetDStream() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_resetDStream(ZSTD_DStream* dctx) +{ + FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); + return ZSTD_startingInputLength(dctx->format); +} + + +size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (ddict) { + dctx->ddict = ddict; + dctx->dictUses = ZSTD_use_indefinitely; + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { + if (dctx->ddictSet == NULL) { + dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); + if (!dctx->ddictSet) { + RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); + } + } + assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ + FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); + } + } + return 0; +} + +/* ZSTD_DCtx_setMaxWindowSize() : + * note : no direct equivalence in ZSTD_DCtx_setParameter, + * since this version sets windowSize, and the other sets windowLog */ +size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax); + size_t const min = (size_t)1 << bounds.lowerBound; + size_t const max = (size_t)1 << bounds.upperBound; + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, ""); + RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, ""); + dctx->maxWindowSize = maxWindowSize; + return 0; +} + +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) +{ + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); +} + +ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) +{ + ZSTD_bounds bounds = { 0, 0, 0 }; + switch(dParam) { + case ZSTD_d_windowLogMax: + bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN; + bounds.upperBound = ZSTD_WINDOWLOG_MAX; + return bounds; + case ZSTD_d_format: + bounds.lowerBound = (int)ZSTD_f_zstd1; + bounds.upperBound = (int)ZSTD_f_zstd1_magicless; + ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); + return bounds; + case ZSTD_d_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; + case ZSTD_d_refMultipleDDicts: + bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; + bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; + return bounds; + default:; + } + bounds.error = ERROR(parameter_unsupported); + return bounds; +} + +/* ZSTD_dParam_withinBounds: + * @return 1 if value is within dParam bounds, + * 0 otherwise */ +static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam); + if (ZSTD_isError(bounds.error)) return 0; + if (value < bounds.lowerBound) return 0; + if (value > bounds.upperBound) return 0; + return 1; +} + +#define CHECK_DBOUNDS(p,v) { \ + RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ +} + +size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) +{ + switch (param) { + case ZSTD_d_windowLogMax: + *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); + return 0; + case ZSTD_d_format: + *value = (int)dctx->format; + return 0; + case ZSTD_d_stableOutBuffer: + *value = (int)dctx->outBufferMode; + return 0; + case ZSTD_d_forceIgnoreChecksum: + *value = (int)dctx->forceIgnoreChecksum; + return 0; + case ZSTD_d_refMultipleDDicts: + *value = (int)dctx->refMultipleDDicts; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + switch(dParam) { + case ZSTD_d_windowLogMax: + if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT; + CHECK_DBOUNDS(ZSTD_d_windowLogMax, value); + dctx->maxWindowSize = ((size_t)1) << value; + return 0; + case ZSTD_d_format: + CHECK_DBOUNDS(ZSTD_d_format, value); + dctx->format = (ZSTD_format_e)value; + return 0; + case ZSTD_d_stableOutBuffer: + CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); + dctx->outBufferMode = (ZSTD_bufferMode_e)value; + return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; + case ZSTD_d_refMultipleDDicts: + CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); + if (dctx->staticSize != 0) { + RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); + } + dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) +{ + if ( (reset == ZSTD_reset_session_only) + || (reset == ZSTD_reset_session_and_parameters) ) { + dctx->streamStage = zdss_init; + dctx->noForwardProgress = 0; + } + if ( (reset == ZSTD_reset_parameters) + || (reset == ZSTD_reset_session_and_parameters) ) { + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + ZSTD_DCtx_resetParameters(dctx); + } + return 0; +} + + +size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) +{ + return ZSTD_sizeof_DCtx(dctx); +} + +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +{ + size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/ + unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2); + unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); + size_t const minRBSize = (size_t) neededSize; + RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, + frameParameter_windowTooLarge, ""); + return minRBSize; +} + +size_t ZSTD_estimateDStreamSize(size_t windowSize) +{ + size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + size_t const inBuffSize = blockSize; /* no block can be larger */ + size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN); + return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; +} + +size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) +{ + U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */ + ZSTD_frameHeader zfh; + size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(err)) return err; + RETURN_ERROR_IF(err>0, srcSize_wrong, ""); + RETURN_ERROR_IF(zfh.windowSize > windowSizeMax, + frameParameter_windowTooLarge, ""); + return ZSTD_estimateDStreamSize((size_t)zfh.windowSize); +} + + +/* ***** Decompression ***** */ + +static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR; +} + +static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) + zds->oversizedDuration++; + else + zds->oversizedDuration = 0; +} + +static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds) +{ + return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION; +} + +/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */ +static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output) +{ + ZSTD_outBuffer const expect = zds->expectedOutBuffer; + /* No requirement when ZSTD_obm_stable is not enabled. */ + if (zds->outBufferMode != ZSTD_bm_stable) + return 0; + /* Any buffer is allowed in zdss_init, this must be the same for every other call until + * the context is reset. + */ + if (zds->streamStage == zdss_init) + return 0; + /* The buffer must match our expectation exactly. */ + if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) + return 0; + RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); +} + +/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() + * and updates the stage and the output buffer state. This call is extracted so it can be + * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode. + * NOTE: You must break after calling this function since the streamStage is modified. + */ +static size_t ZSTD_decompressContinueStream( + ZSTD_DStream* zds, char** op, char* oend, + void const* src, size_t srcSize) { + int const isSkipFrame = ZSTD_isSkipFrame(zds); + if (zds->outBufferMode == ZSTD_bm_buffered) { + size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; + size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + if (!decodedSize && !isSkipFrame) { + zds->streamStage = zdss_read; + } else { + zds->outEnd = zds->outStart + decodedSize; + zds->streamStage = zdss_flush; + } + } else { + /* Write directly into the output buffer */ + size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); + size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + *op += decodedSize; + /* Flushing is not needed. */ + zds->streamStage = zdss_read; + assert(*op <= oend); + assert(zds->outBufferMode == ZSTD_bm_stable); + } + return 0; +} + +size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + const char* const src = (const char*)input->src; + const char* const istart = input->pos != 0 ? src + input->pos : src; + const char* const iend = input->size != 0 ? src + input->size : src; + const char* ip = istart; + char* const dst = (char*)output->dst; + char* const ostart = output->pos != 0 ? dst + output->pos : dst; + char* const oend = output->size != 0 ? dst + output->size : dst; + char* op = ostart; + U32 someMoreWork = 1; + + DEBUGLOG(5, "ZSTD_decompressStream"); + RETURN_ERROR_IF( + input->pos > input->size, + srcSize_wrong, + "forbidden. in: pos: %u vs size: %u", + (U32)input->pos, (U32)input->size); + RETURN_ERROR_IF( + output->pos > output->size, + dstSize_tooSmall, + "forbidden. out: pos: %u vs size: %u", + (U32)output->pos, (U32)output->size); + DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); + FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), ""); + + while (someMoreWork) { + switch(zds->streamStage) + { + case zdss_init : + DEBUGLOG(5, "stage zdss_init => transparent reset "); + zds->streamStage = zdss_loadHeader; + zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + zds->legacyVersion = 0; +#endif + zds->hostageByte = 0; + zds->expectedOutBuffer = *output; + ZSTD_FALLTHROUGH; + + case zdss_loadHeader : + DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + if (zds->legacyVersion) { + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; + return hint; + } } +#endif + { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); + if (zds->refMultipleDDicts && zds->ddictSet) { + ZSTD_DCtx_selectFrameDDict(zds); + } + DEBUGLOG(5, "header size : %u", (U32)hSize); + if (ZSTD_isError(hSize)) { +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); + if (legacyVersion) { + ZSTD_DDict const* const ddict = ZSTD_getDDict(zds); + const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL; + size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0; + DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion); + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext, + zds->previousLegacyVersion, legacyVersion, + dict, dictSize), ""); + zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */ + return hint; + } } +#endif + return hSize; /* error */ + } + if (hSize != 0) { /* need more input */ + size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ + size_t const remainingInput = (size_t)(iend-ip); + assert(iend >= ip); + if (toLoad > remainingInput) { /* not enough input to load full header */ + if (remainingInput > 0) { + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + zds->lhSize += remainingInput; + } + input->pos = input->size; + return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + } + assert(ip != NULL); + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + break; + } } + + /* check for single-pass mode opportunity */ + if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && zds->fParams.frameType != ZSTD_skippableFrame + && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { + size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart)); + if (cSize <= (size_t)(iend-istart)) { + /* shortcut : using single-pass mode */ + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); + if (ZSTD_isError(decompressedSize)) return decompressedSize; + DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") + ip = istart + cSize; + op += decompressedSize; + zds->expected = 0; + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } } + + /* Check output buffer is large enough for ZSTD_odm_stable. */ + if (zds->outBufferMode == ZSTD_bm_stable + && zds->fParams.frameType != ZSTD_skippableFrame + && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { + RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small"); + } + + /* Consume header (see ZSTDds_decodeFrameHeader) */ + DEBUGLOG(4, "Consume header"); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); + + if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); + zds->stage = ZSTDds_skipFrame; + } else { + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); + zds->expected = ZSTD_blockHeaderSize; + zds->stage = ZSTDds_decodeBlockHeader; + } + + /* control buffer memory usage */ + DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)", + (U32)(zds->fParams.windowSize >>10), + (U32)(zds->maxWindowSize >> 10) ); + zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); + RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, + frameParameter_windowTooLarge, ""); + + /* Adapt buffer sizes to frame header instructions */ + { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered + ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) + : 0; + + ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); + + { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); + int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); + + if (tooSmall || tooLarge) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)neededInBuffSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutBuffSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + RETURN_ERROR_IF( + bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), + memory_allocation, ""); + } else { + ZSTD_customFree(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); + RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); + } + zds->inBuffSize = neededInBuffSize; + zds->outBuff = zds->inBuff + zds->inBuffSize; + zds->outBuffSize = neededOutBuffSize; + } } } + zds->streamStage = zdss_read; + ZSTD_FALLTHROUGH; + + case zdss_read: + DEBUGLOG(5, "stage zdss_read"); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); + DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); + if (neededInSize==0) { /* end of frame */ + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } + if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); + ip += neededInSize; + /* Function modifies the stage so we must break */ + break; + } } + if (ip==iend) { someMoreWork = 0; break; } /* no more input */ + zds->streamStage = zdss_load; + ZSTD_FALLTHROUGH; + + case zdss_load: + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); + size_t const toLoad = neededInSize - zds->inPos; + int const isSkipFrame = ZSTD_isSkipFrame(zds); + size_t loadedSize; + /* At this point we shouldn't be decompressing a block that we can stream. */ + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip)); + if (isSkipFrame) { + loadedSize = MIN(toLoad, (size_t)(iend-ip)); + } else { + RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, + corruption_detected, + "should never happen"); + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); + } + ip += loadedSize; + zds->inPos += loadedSize; + if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ + + /* decode loaded input */ + zds->inPos = 0; /* input is consumed */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), ""); + /* Function modifies the stage so we must break */ + break; + } + case zdss_flush: + { size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); + op += flushedSize; + zds->outStart += flushedSize; + if (flushedSize == toFlushSize) { /* flush completed */ + zds->streamStage = zdss_read; + if ( (zds->outBuffSize < zds->fParams.frameContentSize) + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", + (int)(zds->outBuffSize - zds->outStart), + (U32)zds->fParams.blockSizeMax); + zds->outStart = zds->outEnd = 0; + } + break; + } } + /* cannot complete flush */ + someMoreWork = 0; + break; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + } } + + /* result */ + input->pos = (size_t)(ip - (const char*)(input->src)); + output->pos = (size_t)(op - (char*)(output->dst)); + + /* Update the expected output buffer for ZSTD_obm_stable. */ + zds->expectedOutBuffer = *output; + + if ((ip==istart) && (op==ostart)) { /* no forward progress */ + zds->noForwardProgress ++; + if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { + RETURN_ERROR_IF(op==oend, dstSize_tooSmall, ""); + RETURN_ERROR_IF(ip==iend, srcSize_wrong, ""); + assert(0); + } + } else { + zds->noForwardProgress = 0; + } + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds); + if (!nextSrcSizeHint) { /* frame fully decoded */ + if (zds->outEnd == zds->outStart) { /* output fully flushed */ + if (zds->hostageByte) { + if (input->pos >= input->size) { + /* can't release hostage (not present) */ + zds->streamStage = zdss_read; + return 1; + } + input->pos++; /* release hostage */ + } /* zds->hostageByte */ + return 0; + } /* zds->outEnd == zds->outStart */ + if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ + input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ + zds->hostageByte=1; + } + return 1; + } /* nextSrcSizeHint==0 */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ + assert(zds->inPos <= nextSrcSizeHint); + nextSrcSizeHint -= zds->inPos; /* part already loaded*/ + return nextSrcSizeHint; + } +} + +size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos) +{ + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; +} diff --git a/stage1/zstd/lib/decompress/zstd_decompress_block.c b/stage1/zstd/lib/decompress/zstd_decompress_block.c new file mode 100644 index 000000000000..2e44d30d2f37 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_block.c @@ -0,0 +1,2072 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_decompress_block : + * this module takes care of decompressing _compressed_ block */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/compiler.h" /* prefetch */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/zstd_internal.h" +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" + +/*_******************************************************* +* Macros +**********************************************************/ + +/* These two optional macros force the use one way or another of the two + * ZSTD_decompressSequences implementations. You can't force in both directions + * at the same time. + */ +#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!" +#endif + + +/*_******************************************************* +* Memory operations +**********************************************************/ +static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } + + +/*-************************************************************* + * Block decoding + ***************************************************************/ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr) +{ + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); + + { U32 const cBlockHeader = MEM_readLE24(src); + U32 const cSize = cBlockHeader >> 3; + bpPtr->lastBlock = cBlockHeader & 1; + bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); + bpPtr->origSize = cSize; /* only useful for RLE */ + if (bpPtr->blockType == bt_rle) return 1; + RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, ""); + return cSize; + } +} + +/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ +static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, + const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) +{ + if (streaming == not_streaming && dstCapacity > ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) + { + /* room for litbuffer to fit without read faulting */ + dctx->litBuffer = (BYTE*)dst + ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_in_dst; + } + else if (litSize > ZSTD_LITBUFFEREXTRASIZE) + { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + if (splitImmediately) { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; + } + else { + /* initially this will be stored entirely in dst during huffman decoding, it will partially shifted to litExtraBuffer after */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; + dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; + } + dctx->litBufferLocation = ZSTD_split; + } + else + { + /* fits entirely within litExtraBuffer, so no split is necessary */ + dctx->litBuffer = dctx->litExtraBuffer; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + } +} + +/* Hidden declaration for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, + void* dst, size_t dstCapacity, const streaming_operation streaming); +/*! ZSTD_decodeLiteralsBlock() : + * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored + * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current + * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being + * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. + * + * @return : nb of bytes read from src (< srcSize ) + * note : symbol not declared but exposed for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ + void* dst, size_t dstCapacity, const streaming_operation streaming) +{ + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); + RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); + + { const BYTE* const istart = (const BYTE*) src; + symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); + + switch(litEncType) + { + case set_repeat: + DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); + RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); + ZSTD_FALLTHROUGH; + + case set_compressed: + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); + { size_t lhSize, litSize, litCSize; + U32 singleStream=0; + U32 const lhlCode = (istart[0] >> 2) & 3; + U32 const lhc = MEM_readLE32(istart); + size_t hufSuccess; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ + /* 2 - 2 - 10 - 10 */ + singleStream = !lhlCode; + lhSize = 3; + litSize = (lhc >> 4) & 0x3FF; + litCSize = (lhc >> 14) & 0x3FF; + break; + case 2: + /* 2 - 2 - 14 - 14 */ + lhSize = 4; + litSize = (lhc >> 4) & 0x3FFF; + litCSize = lhc >> 18; + break; + case 3: + /* 2 - 2 - 18 - 18 */ + lhSize = 5; + litSize = (lhc >> 4) & 0x3FFFF; + litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); + + /* prefetch huffman table if cold */ + if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { + PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable)); + } + + if (litEncType==set_repeat) { + if (singleStream) { + hufSuccess = HUF_decompress1X_usingDTable_bmi2( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); + } else { + hufSuccess = HUF_decompress4X_usingDTable_bmi2( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); + } + } else { + if (singleStream) { +#if defined(HUF_FORCE_DECOMPRESS_X2) + hufSuccess = HUF_decompress1X_DCtx_wksp( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace)); +#else + hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); +#endif + } else { + hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); + } + } + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); + dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; + } + + RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); + + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + dctx->litEntropy = 1; + if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; + return litCSize + lhSize; + } + + case set_basic: + { size_t litSize, lhSize; + U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + litSize = MEM_readLE24(istart) >> 4; + break; + } + + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ + RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+litSize; + } + /* direct reference into compressed stream */ + dctx->litPtr = istart+lhSize; + dctx->litSize = litSize; + dctx->litBufferEnd = dctx->litPtr + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + return lhSize+litSize; + } + + case set_rle: + { U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t litSize, lhSize; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + litSize = MEM_readLE24(istart) >> 4; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+1; + } + default: + RETURN_ERROR(corruption_detected, "impossible"); + } + } +} + +/* Default FSE distribution tables. + * These are pre-calculated FSE decoding tables using default distributions as defined in specification : + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions + * They were generated programmatically with following method : + * - start from default distributions, present in /lib/common/zstd_internal.h + * - generate tables normally, using ZSTD_buildFSETable() + * - printout the content of tables + * - pretify output, report below, test with fuzzer to ensure it's correct */ + +/* Default FSE distribution table for Literal Lengths */ +static const ZSTD_seqSymbol LL_defaultDTable[(1<tableLog = 0; + DTableH->fastMode = 0; + + cell->nbBits = 0; + cell->nextState = 0; + assert(nbAddBits < 255); + cell->nbAdditionalBits = nbAddBits; + cell->baseValue = baseValue; +} + + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * cannot fail if input is valid => + * all inputs are presumed validated at this stage */ +FORCE_INLINE_TEMPLATE +void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize) +{ + ZSTD_seqSymbol* const tableDecode = dt+1; + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + + U16* symbolNext = (U16*)wksp; + BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); + U32 highThreshold = tableSize - 1; + + + /* Sanity Checks */ + assert(maxSymbolValue <= MaxSeq); + assert(tableLog <= MaxFSELog); + assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); + (void)wkspSize; + /* Init, lay down lowprob symbols */ + { ZSTD_seqSymbol_header DTableH; + DTableH.tableLog = tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + assert(normalizedCounter[s]>=0); + symbolNext[s] = (U16)normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + assert(tableSize <= 512); + /* Specialized symbol spreading for the case when there are + * no low probability (-1 count) symbols. When compressing + * small blocks we avoid low probability symbols to hit this + * case, since header decoding speed matters more. + */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { + U32 u; + for (u=0; u max, corruption_detected, ""); + { U32 const symbol = *(const BYTE*)src; + U32 const baseline = baseValue[symbol]; + U8 const nbBits = nbAdditionalBits[symbol]; + ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); + } + *DTablePtr = DTableSpace; + return 1; + case set_basic : + *DTablePtr = defaultTable; + return 0; + case set_repeat: + RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, ""); + /* prefetch FSE table if used */ + if (ddictIsCold && (nbSeq > 24 /* heuristic */)) { + const void* const pStart = *DTablePtr; + size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog)); + PREFETCH_AREA(pStart, pSize); + } + return 0; + case set_compressed : + { unsigned tableLog; + S16 norm[MaxSeq+1]; + size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); + RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); + RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); + *DTablePtr = DTableSpace; + return headerSize; + } + default : + assert(0); + RETURN_ERROR(GENERIC, "impossible"); + } +} + +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize) +{ + const BYTE* const istart = (const BYTE*)src; + const BYTE* const iend = istart + srcSize; + const BYTE* ip = istart; + int nbSeq; + DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); + + /* check */ + RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, ""); + + /* SeqHead */ + nbSeq = *ip++; + if (!nbSeq) { + *nbSeqPtr=0; + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); + return 1; + } + if (nbSeq > 0x7F) { + if (nbSeq == 0xFF) { + RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); + nbSeq = MEM_readLE16(ip) + LONGNBSEQ; + ip+=2; + } else { + RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); + nbSeq = ((nbSeq-0x80)<<8) + *ip++; + } + } + *nbSeqPtr = nbSeq; + + /* FSE table descriptors */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ + { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); + symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); + symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); + ip++; + + /* Build DTables */ + { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, + LLtype, MaxLL, LLFSELog, + ip, iend-ip, + LL_base, LL_bits, + LL_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += llhSize; + } + + { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, + OFtype, MaxOff, OffFSELog, + ip, iend-ip, + OF_base, OF_bits, + OF_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += ofhSize; + } + + { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, + MLtype, MaxML, MLFSELog, + ip, iend-ip, + ML_base, ML_bits, + ML_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += mlhSize; + } + } + + return ip-istart; +} + + +typedef struct { + size_t litLength; + size_t matchLength; + size_t offset; +} seq_t; + +typedef struct { + size_t state; + const ZSTD_seqSymbol* table; +} ZSTD_fseState; + +typedef struct { + BIT_DStream_t DStream; + ZSTD_fseState stateLL; + ZSTD_fseState stateOffb; + ZSTD_fseState stateML; + size_t prevOffset[ZSTD_REP_NUM]; +} seqState_t; + +/*! ZSTD_overlapCopy8() : + * Copies 8 bytes from ip to op and updates op and ip where ip <= op. + * If the offset is < 8 then the offset is spread to at least 8 bytes. + * + * Precondition: *ip <= *op + * Postcondition: *op - *op >= 8 + */ +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { + assert(*ip <= *op); + if (offset < 8) { + /* close range match, overlap */ + static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ + static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */ + int const sub2 = dec64table[offset]; + (*op)[0] = (*ip)[0]; + (*op)[1] = (*ip)[1]; + (*op)[2] = (*ip)[2]; + (*op)[3] = (*ip)[3]; + *ip += dec32table[offset]; + ZSTD_copy4(*op+4, *ip); + *ip -= sub2; + } else { + ZSTD_copy8(*op, *ip); + } + *ip += 8; + *op += 8; + assert(*op - *ip >= 8); +} + +/*! ZSTD_safecopy() : + * Specialized version of memcpy() that is allowed to READ up to WILDCOPY_OVERLENGTH past the input buffer + * and write up to 16 bytes past oend_w (op >= oend_w is allowed). + * This function is only called in the uncommon case where the sequence is near the end of the block. It + * should be fast for a single long sequence, but can be slow for several short sequences. + * + * @param ovtype controls the overlap detection + * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart. + * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. + * The src buffer must be before the dst buffer. + */ +static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + assert((ovtype == ZSTD_no_overlap && (diff <= -8 || diff >= 8 || op >= oend_w)) || + (ovtype == ZSTD_overlap_src_before_dst && diff >= 0)); + + if (length < 8) { + /* Handle short lengths. */ + while (op < oend) *op++ = *ip++; + return; + } + if (ovtype == ZSTD_overlap_src_before_dst) { + /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ + assert(length >= 8); + ZSTD_overlapCopy8(&op, &ip, diff); + length -= 8; + assert(op - ip >= 8); + assert(op <= oend); + } + + if (oend <= oend_w) { + /* No risk of overwrite. */ + ZSTD_wildcopy(op, ip, length, ovtype); + return; + } + if (op <= oend_w) { + /* Wildcopy until we get close to the end. */ + assert(oend > oend_w); + ZSTD_wildcopy(op, ip, oend_w - op, ovtype); + ip += oend_w - op; + op += oend_w - op; + } + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_safecopyDstBeforeSrc(): + * This version allows overlap with dst before src, or handles the non-overlap case with dst after src + * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + if (length < 8 || diff > -8) { + /* Handle short lengths, close overlaps, and dst not before src. */ + while (op < oend) *op++ = *ip++; + return; + } + + if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { + ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ip += oend - WILDCOPY_OVERLENGTH - op; + op += oend - WILDCOPY_OVERLENGTH - op; + } + + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_execSequenceEnd(): + * This version handles cases that are near the end of the output buffer. It requires + * more careful checks to make sure there is no overflow. By separating out these hard + * and unlikely cases, we can speed up the common cases. + * + * NOTE: This function needs to be fast for a single long sequence, but doesn't need + * to be optimized for many small sequences, since those fall into ZSTD_execSequence(). + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEnd(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +/* ZSTD_execSequenceEndSplitLitBuffer(): + * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); + ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequence(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + + +static void +ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) +{ + const void* ptr = dt; + const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits", + (U32)DStatePtr->state, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +FORCE_INLINE_TEMPLATE void +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) +{ + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = nextState + lowBits; +} + +/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum + * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1) + * bits before reloading. This value is the maximum number of bytes we read + * after reloading when we are decoding long offsets. + */ +#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \ + (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \ + ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \ + : 0) + +typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; + +FORCE_INLINE_TEMPLATE seq_t +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) +{ + seq_t seq; + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + /* + * As gcc has better branch and block analyzers, sometimes it is only + * valuable to mark likelyness for clang, it gives around 3-4% of + * performance. + */ + + /* sequence */ + { size_t offset; + #if defined(__clang__) + if (LIKELY(ofBits > 1)) { + #else + if (ofBits > 1) { + #endif + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } else { + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + offset = seqState->prevOffset[ll0]; + seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + seqState->prevOffset[0] = offset; + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; + } + + #if defined(__clang__) + if (UNLIKELY(mlBits > 0)) + #else + if (mlBits > 0) + #endif + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + #if defined(__clang__) + if (UNLIKELY(llBits > 0)) + #else + if (llBits > 0) + #endif + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + } + + return seq; +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) +{ + size_t const windowSize = dctx->fParams.windowSize; + /* No dictionary used. */ + if (dctx->dictContentEndForFuzzing == NULL) return 0; + /* Dictionary is our prefix. */ + if (prefixStart == dctx->dictContentBeginForFuzzing) return 1; + /* Dictionary is not our ext-dict. */ + if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0; + /* Dictionary is not within our window size. */ + if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0; + /* Dictionary is active. */ + return 1; +} + +MEM_STATIC void ZSTD_assertValidSequence( + ZSTD_DCtx const* dctx, + BYTE const* op, BYTE const* oend, + seq_t const seq, + BYTE const* prefixStart, BYTE const* virtualStart) +{ +#if DEBUGLEVEL >= 1 + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); + } +#else + (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; +#endif +} +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer"); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i=0; ientropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + + /* decompress without overrunning litPtr begins */ + { + seq_t sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * This issue has been reproduced on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * - Coffeelake: Intel i7-9700k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * Alignment is done for each of the three major decompression loops: + * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer + * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer + * - ZSTD_decompressSequences_body + * Alignment choices are made to minimize large swings on bad cases and influence on performance + * from changes external to this code, rather than to overoptimize on the current commit. + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); +# if __GNUC__ >= 7 + /* good for gcc-7, gcc-9, and gcc-11 */ + __asm__("nop"); + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); +# if __GNUC__ == 8 || __GNUC__ == 10 + /* good for gcc-8 and gcc-10 */ + __asm__("nop"); + __asm__(".p2align 3"); +# endif +# endif +#endif + + /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ + for (; litPtr + sequence.litLength <= dctx->litBufferEnd; ) { + size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + } + + /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ + if (nbSeq > 0) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence.litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (--nbSeq) + BIT_reloadDStream(&(seqState.DStream)); + } + } + } + + if (nbSeq > 0) /* there is remaining lit from extra buffer */ + { + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ != 7 + /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# elif __GNUC__ >= 11 + __asm__(".p2align 3"); +# else + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for (; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ostart + maxDstSize : dctx->litBuffer; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); + const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_body"); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ >= 7 + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# else + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + { size_t const lastLLSize = litEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} + +static size_t +ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + +FORCE_INLINE_TEMPLATE size_t +ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, + const BYTE* const prefixStart, const BYTE* const dictEnd) +{ + prefetchPos += sequence.litLength; + { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; + const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : memory address is only used for prefetching, not for dereferencing */ + PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + } + return prefetchPos + sequence.matchLength; +} + +/* This decoding function employs prefetching + * to reduce latency impact of cache misses. + * It's generally employed when block contains a significant portion of long-distance matches + * or when coupled with a "cold" dictionary */ +FORCE_INLINE_TEMPLATE size_t +ZSTD_decompressSequencesLong_body( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { +#define STORED_SEQS 8 +#define STORED_SEQS_MASK (STORED_SEQS-1) +#define ADVANCED_SEQS STORED_SEQS + seq_t sequences[STORED_SEQS]; + int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); + seqState_t seqState; + int seqNb; + size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ + + dctx->fseEntropy = 1; + { int i; for (i=0; ientropy.rep[i]; } + assert(dst != NULL); + assert(iend >= ip); + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + + /* prepare in advance */ + for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) + { + /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + else + { + /* lit buffer is either wholly contained in first or second split, or not split at all*/ + oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + } + RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) + { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence->litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + else + { + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* first deplete literal buffer in dst, then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + + +#if DYNAMIC_BMI2 + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +static BMI2_TARGET_ATTRIBUTE size_t +ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + +#endif /* DYNAMIC_BMI2 */ + +typedef size_t (*ZSTD_decompressSequences_t)( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame); + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static size_t +ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequences"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static size_t +ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +/* ZSTD_decompressSequencesLong() : + * decompression function triggered when a minimum share of offsets is considered "long", + * aka out of cache. + * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes meaning "farther than memory cache distance". + * This function will try to mitigate main memory latency through the use of prefetching */ +static size_t +ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesLong"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +/* ZSTD_getLongOffsetsShare() : + * condition : offTable must be valid + * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) + * compared to maximum possible of (1< 22) total += 1; + } + + assert(tableLog <= OffFSELog); + total <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + + return total; +} +#endif + +size_t +ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming) +{ /* blockType == blockCompressed */ + const BYTE* ip = (const BYTE*)src; + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. + * We don't expect that to be the case in 64-bit mode. + * In block mode, window size is not known, so we have to be conservative. + * (note: but it could be evaluated from current-lowLimit) + */ + ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); + DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); + + RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); + + /* Decode literals section */ + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); + if (ZSTD_isError(litCSize)) return litCSize; + ip += litCSize; + srcSize -= litCSize; + } + + /* Build Decoding Tables */ + { + /* These macros control at build-time which decompressor implementation + * we use. If neither is defined, we do some inspection and dispatch at + * runtime. + */ +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + int usePrefetchDecoder = dctx->ddictIsCold; +#endif + int nbSeq; + size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); + if (ZSTD_isError(seqHSize)) return seqHSize; + ip += seqHSize; + srcSize -= seqHSize; + + RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if ( !usePrefetchDecoder + && (!frame || (dctx->fParams.windowSize > (1<<24))) + && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */ + U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr); + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (shareLongOffsets >= minShare); + } +#endif + + dctx->ddictIsCold = 0; + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if (usePrefetchDecoder) +#endif +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + /* else */ + if (dctx->litBufferLocation == ZSTD_split) + return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + else + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + } +} + + +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) +{ + if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dst; + dctx->previousDstEnd = dst; + } +} + + +size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + size_t dSize; + ZSTD_checkContinuity(dctx, dst, dstCapacity); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0, not_streaming); + dctx->previousDstEnd = (char*)dst + dSize; + return dSize; +} diff --git a/stage1/zstd/lib/decompress/zstd_decompress_block.h b/stage1/zstd/lib/decompress/zstd_decompress_block.h new file mode 100644 index 000000000000..c61a9d0c4b36 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_block.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DEC_BLOCK_H +#define ZSTD_DEC_BLOCK_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* DCtx, and some public functions */ +#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */ +#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ + + +/* === Prototypes === */ + +/* note: prototypes already published within `zstd.h` : + * ZSTD_decompressBlock() + */ + +/* note: prototypes already published within `zstd_internal.h` : + * ZSTD_getcBlockSize() + * ZSTD_decodeSeqHeaders() + */ + + + /* Streaming state is used to inform allocation of the literal buffer */ +typedef enum { + not_streaming = 0, + is_streaming = 1 +} streaming_operation; + +/* ZSTD_decompressBlock_internal() : + * decompress block, starting at `src`, + * into destination buffer `dst`. + * @return : decompressed block size, + * or an error code (which can be tested using ZSTD_isError()) + */ +size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming); + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * this function must be called with valid parameters only + * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) + * in which case it cannot fail. + * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is + * defined in zstd_decompress_internal.h. + * Internal use only. + */ +void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize, + int bmi2); + + +#endif /* ZSTD_DEC_BLOCK_H */ diff --git a/stage1/zstd/lib/decompress/zstd_decompress_internal.h b/stage1/zstd/lib/decompress/zstd_decompress_internal.h new file mode 100644 index 000000000000..2b5a53850ac2 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_internal.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* zstd_decompress_internal: + * objects and definitions shared within lib/decompress modules */ + + #ifndef ZSTD_DECOMPRESS_INTERNAL_H + #define ZSTD_DECOMPRESS_INTERNAL_H + + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/mem.h" /* BYTE, U16, U32 */ +#include "../common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ + + + +/*-******************************************************* + * Constants + *********************************************************/ +static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, + 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + +static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { + 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, + 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, + 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, + 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; + +static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 }; + +static UNUSED_ATTR const U32 ML_base[MaxML+1] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 37, 39, 41, 43, 47, 51, 59, + 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; + + +/*-******************************************************* + * Decompression types + *********************************************************/ + typedef struct { + U32 fastMode; + U32 tableLog; + } ZSTD_seqSymbol_header; + + typedef struct { + U16 nextState; + BYTE nbAdditionalBits; + BYTE nbBits; + U32 baseValue; + } ZSTD_seqSymbol; + + #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) + +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) + +typedef struct { + ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ + ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ + ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + U32 rep[ZSTD_REP_NUM]; + U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; +} ZSTD_entropyDTables_t; + +typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, + ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock, + ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, + ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; + +typedef enum { zdss_init=0, zdss_loadHeader, + zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; + +typedef enum { + ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */ + ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */ + ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ +} ZSTD_dictUses_e; + +/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ +typedef struct { + const ZSTD_DDict** ddictPtrTable; + size_t ddictPtrTableSize; + size_t ddictPtrCount; +} ZSTD_DDictHashSet; + +#ifndef ZSTD_DECODER_INTERNAL_BUFFER +# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) +#endif + +#define ZSTD_LBMIN 64 +#define ZSTD_LBMAX (128 << 10) + +/* extra buffer, compensates when dst is not large enough to store litBuffer */ +#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) + +typedef enum { + ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ + ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ + ZSTD_split = 2 /* Split between litExtraBuffer and dst */ +} ZSTD_litLocation_e; + +struct ZSTD_DCtx_s +{ + const ZSTD_seqSymbol* LLTptr; + const ZSTD_seqSymbol* MLTptr; + const ZSTD_seqSymbol* OFTptr; + const HUF_DTable* HUFptr; + ZSTD_entropyDTables_t entropy; + U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */ + const void* previousDstEnd; /* detect continuity */ + const void* prefixStart; /* start of current segment */ + const void* virtualStart; /* virtual start of previous segment if it was just before current one */ + const void* dictEnd; /* end of previous segment */ + size_t expected; + ZSTD_frameHeader fParams; + U64 processedCSize; + U64 decodedSize; + blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ + ZSTD_dStage stage; + U32 litEntropy; + U32 fseEntropy; + XXH64_state_t xxhState; + size_t headerSize; + ZSTD_format_e format; + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ + const BYTE* litPtr; + ZSTD_customMem customMem; + size_t litSize; + size_t rleSize; + size_t staticSize; +#if DYNAMIC_BMI2 != 0 + int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ +#endif + + /* dictionary */ + ZSTD_DDict* ddictLocal; + const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */ + U32 dictID; + int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ + ZSTD_dictUses_e dictUses; + ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ + ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ + + /* streaming */ + ZSTD_dStreamStage streamStage; + char* inBuff; + size_t inBuffSize; + size_t inPos; + size_t maxWindowSize; + char* outBuff; + size_t outBuffSize; + size_t outStart; + size_t outEnd; + size_t lhSize; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + void* legacyContext; + U32 previousLegacyVersion; + U32 legacyVersion; +#endif + U32 hostageByte; + int noForwardProgress; + ZSTD_bufferMode_e outBufferMode; + ZSTD_outBuffer expectedOutBuffer; + + /* workspace */ + BYTE* litBuffer; + const BYTE* litBufferEnd; + ZSTD_litLocation_e litBufferLocation; + BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ + BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; + + size_t oversizedDuration; + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + void const* dictContentBeginForFuzzing; + void const* dictContentEndForFuzzing; +#endif + + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif +}; /* typedef'd to ZSTD_DCtx within "zstd.h" */ + +MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { +#if DYNAMIC_BMI2 != 0 + return dctx->bmi2; +#else + (void)dctx; + return 0; +#endif +} + +/*-******************************************************* + * Shared internal functions + *********************************************************/ + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ +size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize); + +/*! ZSTD_checkContinuity() : + * check if next `dst` follows previous position, where decompression ended. + * If yes, do nothing (continue on current segment). + * If not, classify previous segment as "external dictionary", and start a new segment. + * This function cannot fail. */ +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); + + +#endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/stage1/zstd/lib/zstd.h b/stage1/zstd/lib/zstd.h new file mode 100644 index 000000000000..a88ae7bf8ed5 --- /dev/null +++ b/stage1/zstd/lib/zstd.h @@ -0,0 +1,2575 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef ZSTD_H_235446 +#define ZSTD_H_235446 + +/* ====== Dependency ======*/ +#include /* INT_MAX */ +#include /* size_t */ + + +/* ===== ZSTDLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDLIB_VISIBLE +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZSTDLIB_VISIBLE +# define ZSTDLIB_HIDDEN +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDLIB_API ZSTDLIB_VISIBLE +#endif + + +/******************************************************************************* + Introduction + + zstd, short for Zstandard, is a fast lossless compression algorithm, targeting + real-time compression scenarios at zlib-level and better compression ratios. + The zstd compression library provides in-memory compression and decompression + functions. + + The library supports regular compression levels from 1 up to ZSTD_maxCLevel(), + which is currently 22. Levels >= 20, labeled `--ultra`, should be used with + caution, as they require more memory. The library also offers negative + compression levels, which extend the range of speed vs. ratio preferences. + The lower the level, the faster the speed (at the cost of compression). + + Compression can be done in: + - a single step (described as Simple API) + - a single step, reusing a context (described as Explicit context) + - unbounded multiple steps (described as Streaming compression) + + The compression ratio achievable on small data can be highly improved using + a dictionary. Dictionary compression can be performed in: + - a single step (described as Simple dictionary API) + - a single step, reusing a dictionary (described as Bulk-processing + dictionary API) + + Advanced experimental functions can be accessed using + `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h. + + Advanced experimental APIs should never be used with a dynamically-linked + library. They are not "stable"; their definitions or signatures may change in + the future. Only static linking is allowed. +*******************************************************************************/ + +/*------ Version ------*/ +#define ZSTD_VERSION_MAJOR 1 +#define ZSTD_VERSION_MINOR 5 +#define ZSTD_VERSION_RELEASE 2 +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) + +/*! ZSTD_versionNumber() : + * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ +ZSTDLIB_API unsigned ZSTD_versionNumber(void); + +#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE +#define ZSTD_QUOTE(str) #str +#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) +#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) + +/*! ZSTD_versionString() : + * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ +ZSTDLIB_API const char* ZSTD_versionString(void); + +/* ************************************* + * Default constant + ***************************************/ +#ifndef ZSTD_CLEVEL_DEFAULT +# define ZSTD_CLEVEL_DEFAULT 3 +#endif + +/* ************************************* + * Constants + ***************************************/ + +/* All magic numbers are supposed read/written to/from files/memory using little-endian convention */ +#define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */ +#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* valid since v0.7.0 */ +#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50 /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */ +#define ZSTD_MAGIC_SKIPPABLE_MASK 0xFFFFFFF0 + +#define ZSTD_BLOCKSIZELOG_MAX 17 +#define ZSTD_BLOCKSIZE_MAX (1<= `ZSTD_compressBound(srcSize)`. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*! ZSTD_decompress() : + * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames. + * `dstCapacity` is an upper bound of originalSize to regenerate. + * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data. + * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), + * or an errorCode if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, + const void* src, size_t compressedSize); + +/*! ZSTD_getFrameContentSize() : requires v1.3.0+ + * `src` should point to the start of a ZSTD encoded frame. + * `srcSize` must be at least as large as the frame header. + * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough. + * @return : - decompressed size of `src` frame content, if known + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) + * note 1 : a 0 return value means the frame is valid but "empty". + * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * Optionally, application can rely on some implicit limit, + * as ZSTD_decompress() only needs an upper bound of decompressed size. + * (For example, data could be necessarily cut into blocks <= 16 KB). + * note 3 : decompressed size is always present when compression is completed using single-pass functions, + * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict(). + * note 4 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure return value fits within application's authorized limits. + * Each application can set its own limits. + * note 6 : This function replaces ZSTD_getDecompressedSize() */ +#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) +#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) +ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); + +/*! ZSTD_getDecompressedSize() : + * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize(). + * Both functions work the same way, but ZSTD_getDecompressedSize() blends + * "empty", "unknown" and "error" results to the same return value (0), + * while ZSTD_getFrameContentSize() gives them separate return values. + * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ +ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ + * `src` should point to the start of a ZSTD frame or skippable frame. + * `srcSize` must be >= first frame size + * @return : the compressed size of the first frame starting at `src`, + * suitable to pass as `srcSize` to `ZSTD_decompress` or similar, + * or an error code if input is invalid */ +ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize); + + +/*====== Helper functions ======*/ +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ +ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ +ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ +ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ + + +/*************************************** +* Explicit context +***************************************/ +/*= Compression context + * When compressing many times, + * it is recommended to allocate a context just once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Note : re-using context is just a speed / resource optimization. + * It doesn't change the compression ratio, which remains identical. + * Note 2 : In multi-threaded environments, + * use one different context per thread for parallel execution. + */ +typedef struct ZSTD_CCtx_s ZSTD_CCtx; +ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ + +/*! ZSTD_compressCCtx() : + * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. + * Important : in order to behave similarly to `ZSTD_compress()`, + * this function compresses at requested compression level, + * __ignoring any other parameter__ . + * If any advanced parameter was set using the advanced API, + * they will all be reset. Only `compressionLevel` remains. + */ +ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*= Decompression context + * When decompressing many times, + * it is recommended to allocate a context only once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Use one context per thread for parallel execution. */ +typedef struct ZSTD_DCtx_s ZSTD_DCtx; +ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ + +/*! ZSTD_decompressDCtx() : + * Same as ZSTD_decompress(), + * requires an allocated ZSTD_DCtx. + * Compatible with sticky parameters. + */ +ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/********************************************* +* Advanced compression API (Requires v1.4.0+) +**********************************************/ + +/* API design : + * Parameters are pushed one by one into an existing context, + * using ZSTD_CCtx_set*() functions. + * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame. + * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` ! + * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ . + * + * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). + * + * This API supersedes all other "advanced" API entry points in the experimental section. + * In the future, we expect to remove from experimental API entry points which are redundant with this API. + */ + + +/* Compression strategies, listed from fastest to strongest */ +typedef enum { ZSTD_fast=1, + ZSTD_dfast=2, + ZSTD_greedy=3, + ZSTD_lazy=4, + ZSTD_lazy2=5, + ZSTD_btlazy2=6, + ZSTD_btopt=7, + ZSTD_btultra=8, + ZSTD_btultra2=9 + /* note : new strategies _might_ be added in the future. + Only the order (from fast to strong) is guaranteed */ +} ZSTD_strategy; + +typedef enum { + + /* compression parameters + * Note: When compressing with a ZSTD_CDict these parameters are superseded + * by the parameters used to construct the ZSTD_CDict. + * See ZSTD_CCtx_refCDict() for more info (superseded-by-cdict). */ + ZSTD_c_compressionLevel=100, /* Set compression parameters according to pre-defined cLevel table. + * Note that exact compression parameters are dynamically determined, + * depending on both compression level and srcSize (when known). + * Default level is ZSTD_CLEVEL_DEFAULT==3. + * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT. + * Note 1 : it's possible to pass a negative compression level. + * Note 2 : setting a level does not automatically set all other compression parameters + * to default. Setting this will however eventually dynamically impact the compression + * parameters which have not been manually set. The manually set + * ones will 'stick'. */ + /* Advanced compression parameters : + * It's possible to pin down compression parameters to some specific values. + * In which case, these values are no longer dynamically selected by the compressor */ + ZSTD_c_windowLog=101, /* Maximum allowed back-reference distance, expressed as power of 2. + * This will set a memory budget for streaming decompression, + * with larger values requiring more memory + * and typically compressing more. + * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. + * Special: value 0 means "use default windowLog". + * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT + * requires explicitly allowing such size at streaming decompression stage. */ + ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2. + * Resulting memory usage is (1 << (hashLog+2)). + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. + * Larger tables improve compression ratio of strategies <= dFast, + * and improve speed of strategies > dFast. + * Special: value 0 means "use default hashLog". */ + ZSTD_c_chainLog=103, /* Size of the multi-probe search table, as a power of 2. + * Resulting memory usage is (1 << (chainLog+2)). + * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX. + * Larger tables result in better and slower compression. + * This parameter is useless for "fast" strategy. + * It's still useful when using "dfast" strategy, + * in which case it defines a secondary probe table. + * Special: value 0 means "use default chainLog". */ + ZSTD_c_searchLog=104, /* Number of search attempts, as a power of 2. + * More attempts result in better and slower compression. + * This parameter is useless for "fast" and "dFast" strategies. + * Special: value 0 means "use default searchLog". */ + ZSTD_c_minMatch=105, /* Minimum size of searched matches. + * Note that Zstandard can still find matches of smaller size, + * it just tweaks its search algorithm to look for this size and larger. + * Larger values increase compression and decompression speed, but decrease ratio. + * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX. + * Note that currently, for all strategies < btopt, effective minimum is 4. + * , for all strategies > fast, effective maximum is 6. + * Special: value 0 means "use default minMatchLength". */ + ZSTD_c_targetLength=106, /* Impact of this field depends on strategy. + * For strategies btopt, btultra & btultra2: + * Length of Match considered "good enough" to stop search. + * Larger values make compression stronger, and slower. + * For strategy fast: + * Distance between match sampling. + * Larger values make compression faster, and weaker. + * Special: value 0 means "use default targetLength". */ + ZSTD_c_strategy=107, /* See ZSTD_strategy enum definition. + * The higher the value of selected strategy, the more complex it is, + * resulting in stronger and slower compression. + * Special: value 0 means "use default strategy". */ + /* LDM mode parameters */ + ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. + * This parameter is designed to improve compression ratio + * for large inputs, by finding large matches at long distance. + * It increases memory usage and window size. + * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB + * except when expressly set to a different value. + * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and + * compression strategy >= ZSTD_btopt (== compression level 16+) */ + ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. + * Larger values increase memory usage and compression ratio, + * but decrease compression speed. + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX + * default: windowlog - 7. + * Special: value 0 means "automatically determine hashlog". */ + ZSTD_c_ldmMinMatch=162, /* Minimum match size for long distance matcher. + * Larger/too small values usually decrease compression ratio. + * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX. + * Special: value 0 means "use default value" (default: 64). */ + ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution. + * Larger values improve collision resolution but decrease compression speed. + * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX. + * Special: value 0 means "use default value" (default: 3). */ + ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table. + * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN). + * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage. + * Larger values improve compression speed. + * Deviating far from default value will likely result in a compression ratio decrease. + * Special: value 0 means "automatically determine hashRateLog". */ + + /* frame parameters */ + ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1) + * Content size must be known at the beginning of compression. + * This is automatically the case when using ZSTD_compress2(), + * For streaming scenarios, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */ + ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */ + ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ + + /* multi-threading parameters */ + /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. + * In a situation where it's unknown if the linked library supports multi-threading or not, + * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. + */ + ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. + * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : + * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, + * while compression is performed in parallel, within worker thread(s). + * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : + * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). + * More workers improve speed, but also increase memory usage. + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, + * compression is performed inside Caller's thread, and all invocations are blocking */ + ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. + * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. + * 0 means default, which is dynamically determined based on compression parameters. + * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. + * The minimum size is automatically and transparently enforced. */ + ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. + * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. + * It helps preserve compression ratio, while each job is compressed in parallel. + * This value is enforced only when nbWorkers >= 1. + * Larger values increase compression ratio, but decrease speed. + * Possible values range from 0 to 9 : + * - 0 means "default" : value will be determined by the library, depending on strategy + * - 1 means "no overlap" + * - 9 means "full overlap", using a full window size. + * Each intermediate rank increases/decreases load size by a factor 2 : + * 9: full window; 8: w/2; 7: w/4; 6: w/8; 5:w/16; 4: w/32; 3:w/64; 2:w/128; 1:no overlap; 0:default + * default value varies between 6 and 9, depending on strategy */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_c_rsyncable + * ZSTD_c_format + * ZSTD_c_forceMaxWindow + * ZSTD_c_forceAttachDict + * ZSTD_c_literalCompressionMode + * ZSTD_c_targetCBlockSize + * ZSTD_c_srcSizeHint + * ZSTD_c_enableDedicatedDictSearch + * ZSTD_c_stableInBuffer + * ZSTD_c_stableOutBuffer + * ZSTD_c_blockDelimiters + * ZSTD_c_validateSequences + * ZSTD_c_useBlockSplitter + * ZSTD_c_useRowMatchFinder + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly; + * also, the enums values themselves are unstable and can still change. + */ + ZSTD_c_experimentalParam1=500, + ZSTD_c_experimentalParam2=10, + ZSTD_c_experimentalParam3=1000, + ZSTD_c_experimentalParam4=1001, + ZSTD_c_experimentalParam5=1002, + ZSTD_c_experimentalParam6=1003, + ZSTD_c_experimentalParam7=1004, + ZSTD_c_experimentalParam8=1005, + ZSTD_c_experimentalParam9=1006, + ZSTD_c_experimentalParam10=1007, + ZSTD_c_experimentalParam11=1008, + ZSTD_c_experimentalParam12=1009, + ZSTD_c_experimentalParam13=1010, + ZSTD_c_experimentalParam14=1011, + ZSTD_c_experimentalParam15=1012 +} ZSTD_cParameter; + +typedef struct { + size_t error; + int lowerBound; + int upperBound; +} ZSTD_bounds; + +/*! ZSTD_cParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - lower and upper bounds, both inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam); + +/*! ZSTD_CCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_cParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is generally only possible during frame initialization (before starting compression). + * Exception : when using multi-threading mode (nbWorkers >= 1), + * the following parameters can be updated _during_ compression (within same frame): + * => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy. + * new parameters will be active for next job only (after a flush()). + * @return : an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtx_setPledgedSrcSize() : + * Total input data size to be compressed as a single frame. + * Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag. + * This value will also be controlled at end of frame, and trigger an error if not respected. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame. + * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. + * ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame. + * Note 2 : pledgedSrcSize is only valid once, for the next frame. + * It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN. + * Note 3 : Whenever all input data is provided and consumed in a single round, + * for example with ZSTD_compress2(), + * or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end), + * this value is automatically overridden by srcSize instead. + */ +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); + +typedef enum { + ZSTD_reset_session_only = 1, + ZSTD_reset_parameters = 2, + ZSTD_reset_session_and_parameters = 3 +} ZSTD_ResetDirective; + +/*! ZSTD_CCtx_reset() : + * There are 2 different things that can be reset, independently or jointly : + * - The session : will stop compressing current frame, and make CCtx ready to start a new one. + * Useful after an error, or to interrupt any ongoing compression. + * Any internal data not yet flushed is cancelled. + * Compression parameters and dictionary remain unchanged. + * They will be used to compress next frame. + * Resetting session never fails. + * - The parameters : changes all parameters back to "default". + * This removes any reference to any dictionary too. + * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) + * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) + * - Both : similar to resetting the session, followed by resetting parameters. + */ +ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); + +/*! ZSTD_compress2() : + * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API. + * ZSTD_compress2() always starts a new frame. + * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - The function is always blocking, returns when compression is completed. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/*********************************************** +* Advanced decompression API (Requires v1.4.0+) +************************************************/ + +/* The advanced API pushes parameters one by one into an existing DCtx context. + * Parameters are sticky, and remain valid for all following frames + * using the same DCtx context. + * It's possible to reset parameters to default values using ZSTD_DCtx_reset(). + * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream(). + * Therefore, no new decompression function is necessary. + */ + +typedef enum { + + ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which + * the streaming API will refuse to allocate memory buffer + * in order to protect the host from unreasonable memory requirements. + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT). + * Special: value 0 means "use default maximum windowLog". */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_d_format + * ZSTD_d_stableOutBuffer + * ZSTD_d_forceIgnoreChecksum + * ZSTD_d_refMultipleDDicts + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly + */ + ZSTD_d_experimentalParam1=1000, + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002, + ZSTD_d_experimentalParam4=1003 + +} ZSTD_dParameter; + +/*! ZSTD_dParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - both lower and upper bounds, inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam); + +/*! ZSTD_DCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_dParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is only possible during frame initialization (before starting decompression). + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value); + +/*! ZSTD_DCtx_reset() : + * Return a DCtx to clean state. + * Session and parameters can be reset jointly or separately. + * Parameters can only be reset when no active frame is being decompressed. + * @return : 0, or an error code, which can be tested with ZSTD_isError() + */ +ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset); + + +/**************************** +* Streaming +****************************/ + +typedef struct ZSTD_inBuffer_s { + const void* src; /**< start of input buffer */ + size_t size; /**< size of input buffer */ + size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_inBuffer; + +typedef struct ZSTD_outBuffer_s { + void* dst; /**< start of output buffer */ + size_t size; /**< size of output buffer */ + size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_outBuffer; + + + +/*-*********************************************************************** +* Streaming compression - HowTo +* +* A ZSTD_CStream object is required to track streaming operation. +* Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources. +* ZSTD_CStream objects can be reused multiple times on consecutive compression operations. +* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. +* +* For parallel execution, use one separate ZSTD_CStream per thread. +* +* note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing. +* +* Parameters are sticky : when starting a new compression on the same context, +* it will re-use the same sticky parameters as previous compression session. +* When in doubt, it's recommended to fully initialize the context before usage. +* Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(), +* ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to +* set more specific parameters, the pledged source size, or load a dictionary. +* +* Use ZSTD_compressStream2() with ZSTD_e_continue as many times as necessary to +* consume input stream. The function will automatically update both `pos` +* fields within `input` and `output`. +* Note that the function may not consume the entire input, for example, because +* the output buffer is already full, in which case `input.pos < input.size`. +* The caller must check if input has been entirely consumed. +* If not, the caller must make some room to receive more compressed data, +* and then present again remaining input data. +* note: ZSTD_e_continue is guaranteed to make some forward progress when called, +* but doesn't guarantee maximal forward progress. This is especially relevant +* when compressing with multiple threads. The call won't block if it can +* consume some input, but if it can't it will wait for some, but not all, +* output to be flushed. +* @return : provides a minimum amount of data remaining to be flushed from internal buffers +* or an error code, which can be tested using ZSTD_isError(). +* +* At any moment, it's possible to flush whatever data might remain stuck within internal buffer, +* using ZSTD_compressStream2() with ZSTD_e_flush. `output->pos` will be updated. +* Note that, if `output->size` is too small, a single invocation with ZSTD_e_flush might not be enough (return code > 0). +* In which case, make some room to receive more compressed data, and call again ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_flush until it returns 0, at which point you can change the +* operation. +* note: ZSTD_e_flush will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if internal buffers are entirely flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* Calling ZSTD_compressStream2() with ZSTD_e_end instructs to finish a frame. +* It will perform a flush and write frame epilogue. +* The epilogue is required for decoders to consider a frame completed. +* flush operation is the same, and follows same rules as calling ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_end until it returns 0, at which point you are free to +* start a new frame. +* note: ZSTD_e_end will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if frame fully completed and fully flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* *******************************************************************/ + +typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */ + /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ +/*===== ZSTD_CStream management functions =====*/ +ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ + +/*===== Streaming compression functions =====*/ +typedef enum { + ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */ + ZSTD_e_flush=1, /* flush any data provided so far, + * it creates (at least) one new block, that can be decoded immediately on reception; + * frame will continue: any future data can still reference previously compressed data, improving compression. + * note : multithreaded compression will block to flush as much output as possible. */ + ZSTD_e_end=2 /* flush any remaining data _and_ close current frame. + * note that frame is only closed after compressed data is fully flushed (return value == 0). + * After that point, any additional data starts a new frame. + * note : each frame is independent (does not reference any content from previous frame). + : note : multithreaded compression will block to flush as much output as possible. */ +} ZSTD_EndDirective; + +/*! ZSTD_compressStream2() : Requires v1.4.0+ + * Behaves about the same as ZSTD_compressStream, with additional control on end directive. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) + * - output->pos must be <= dstCapacity, input->pos must be <= srcSize + * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. + * - endOp must be a valid directive + * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. + * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, + * and then immediately returns, just indicating that there is some data remaining to be flushed. + * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. + * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. + * - @return provides a minimum amount of data remaining to be flushed from internal buffers + * or an error code, which can be tested using ZSTD_isError(). + * if @return != 0, flush is not fully completed, there is still some data left within internal buffers. + * This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers. + * For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed. + * - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0), + * only ZSTD_e_end or ZSTD_e_flush operations are allowed. + * Before starting a new compression job, or changing compression parameters, + * it is required to fully flush internal buffers. + */ +ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + +/* These buffer sizes are softly recommended. + * They are not required : ZSTD_compressStream*() happily accepts any buffer size, for both input and output. + * Respecting the recommended size just makes it a bit easier for ZSTD_compressStream*(), + * reducing the amount of memory shuffling and buffering, resulting in minor performance savings. + * + * However, note that these recommendations are from the perspective of a C caller program. + * If the streaming interface is invoked from some other language, + * especially managed ones such as Java or Go, through a foreign function interface such as jni or cgo, + * a major performance rule is to reduce crossing such interface to an absolute minimum. + * It's not rare that performance ends being spent more into the interface, rather than compression itself. + * In which cases, prefer using large buffers, as large as practical, + * for both input and output, to reduce the nb of roundtrips. + */ +ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block. */ + + +/* ***************************************************************************** + * This following is a legacy streaming API, available since v1.0+ . + * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). + * It is redundant, but remains fully supported. + * Streaming in combination with advanced parameters and dictionary compression + * can only be used through the new API. + ******************************************************************************/ + +/*! + * Equivalent to: + * + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + */ +ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); +/*! + * Alternative for ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue). + * NOTE: The return value is different. ZSTD_compressStream() returns a hint for + * the next read size (if non-zero and not an error). ZSTD_compressStream2() + * returns the minimum nb of bytes left to flush (if non-zero and not an error). + */ +ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */ +ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */ +ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); + + +/*-*************************************************************************** +* Streaming decompression - HowTo +* +* A ZSTD_DStream object is required to track streaming operations. +* Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources. +* ZSTD_DStream objects can be re-used multiple times. +* +* Use ZSTD_initDStream() to start a new decompression operation. +* @return : recommended first input size +* Alternatively, use advanced API to set specific properties. +* +* Use ZSTD_decompressStream() repetitively to consume your input. +* The function will update both `pos` fields. +* If `input.pos < input.size`, some input has not been consumed. +* It's up to the caller to present again remaining data. +* The function tries to flush all data decoded immediately, respecting output buffer size. +* If `output.pos < output.size`, decoder has flushed everything it could. +* But if `output.pos == output.size`, there might be some data left within internal buffers., +* In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer. +* Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX. +* @return : 0 when a frame is completely decoded and fully flushed, +* or an error code, which can be tested using ZSTD_isError(), +* or any other value > 0, which means there is still some decoding or flushing to do to complete current frame : +* the return value is a suggested next input size (just a hint for better latency) +* that will never request more than the remaining frame size. +* *******************************************************************************/ + +typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */ + /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ +/*===== ZSTD_DStream management functions =====*/ +ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ + +/*===== Streaming decompression functions =====*/ + +/* This function is redundant with the advanced API and equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, NULL); + */ +ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); + +ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); + +ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */ + + +/************************** +* Simple dictionary API +***************************/ +/*! ZSTD_compress_usingDict() : + * Compression at an explicit compression level using a Dictionary. + * A dictionary can be any arbitrary data segment (also called a prefix), + * or a buffer with specified information (see zdict.h). + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + int compressionLevel); + +/*! ZSTD_decompress_usingDict() : + * Decompression using a known Dictionary. + * Dictionary must be identical to the one used during compression. + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); + + +/*********************************** + * Bulk processing dictionary API + **********************************/ +typedef struct ZSTD_CDict_s ZSTD_CDict; + +/*! ZSTD_createCDict() : + * When compressing multiple messages or blocks using the same dictionary, + * it's recommended to digest the dictionary only once, since it's a costly operation. + * ZSTD_createCDict() will create a state from digesting a dictionary. + * The resulting state can be used for future compression operations with very limited startup cost. + * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. + * @dictBuffer can be released after ZSTD_CDict creation, because its content is copied within CDict. + * Note 1 : Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate @dictBuffer content. + * Note 2 : A ZSTD_CDict can be created from an empty @dictBuffer, + * in which case the only thing that it transports is the @compressionLevel. + * This can be useful in a pipeline featuring ZSTD_compress_usingCDict() exclusively, + * expecting a ZSTD_CDict parameter with any data, including those without a known dictionary. */ +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, + int compressionLevel); + +/*! ZSTD_freeCDict() : + * Function frees memory allocated by ZSTD_createCDict(). + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); + +/*! ZSTD_compress_usingCDict() : + * Compression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. + * Note : compression level is _decided at dictionary creation time_, + * and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */ +ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict); + + +typedef struct ZSTD_DDict_s ZSTD_DDict; + +/*! ZSTD_createDDict() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * dictBuffer can be released after DDict creation, as its content is copied inside DDict. */ +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_freeDDict() : + * Function frees memory allocated with ZSTD_createDDict() + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); + +/*! ZSTD_decompress_usingDDict() : + * Decompression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict); + + +/******************************** + * Dictionary helper functions + *******************************/ + +/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); + +/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); + +/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); + +/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ + * Provides the dictID required to decompressed the frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary to be decoded (most common case). + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); + + +/******************************************************************************* + * Advanced dictionary and prefix API (Requires v1.4.0+) + * + * This API allows dictionaries to be used with ZSTD_compress2(), + * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). Dictionaries are sticky, and + * only reset with the context is reset with ZSTD_reset_parameters or + * ZSTD_reset_session_and_parameters. Prefixes are single-use. + ******************************************************************************/ + + +/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal CDict from `dict` buffer. + * Decompression will have to use same dictionary. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames. + * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters). + * Note 2 : Loading a dictionary involves building tables. + * It's also a CPU consuming operation, with non-negligible impact on latency. + * Tables are dependent on compression parameters, and for this reason, + * compression parameters can no longer be changed after loading a dictionary. + * Note 3 :`dict` content will be copied internally. + * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. + * In such a case, dictionary buffer must outlive its users. + * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() + * to precisely select how dictionary content must be interpreted. */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used for all next compressed frames. + * Note that compression parameters are enforced from within CDict, + * and supersede any compression parameter previously set within CCtx. + * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. + * The dictionary will remain valid for future compressed frames using same CCtx. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Referencing a NULL CDict means "return to no-dictionary mode". + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. + * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ +ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); + +/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) for next compressed frame. + * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). + * Decompression will need same prefix to properly regenerate data. + * Compressing with a prefix is similar in outcome as performing a diff and compressing it, + * but performs much faster, especially during decompression (compression speed is tunable with compression level). + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary + * Note 1 : Prefix buffer is referenced. It **must** outlive compression. + * Its content must remain unmodified during compression. + * Note 2 : If the intention is to diff some large src data blob with some prior version of itself, + * ensure that the window size is large enough to contain the entire source. + * See ZSTD_c_windowLog. + * Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters. + * It's a CPU consuming operation, with non-negligible impact on latency. + * If there is a need to use the same prefix multiple times, consider loadDictionary instead. + * Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dct_rawContent). + * Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */ +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, + const void* prefix, size_t prefixSize); + +/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal DDict from dict buffer, + * to be used to decompress next frames. + * The dictionary remains valid for all future frames, until explicitly invalidated. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Loading a dictionary involves building tables, + * which has a non-negligible impact on CPU usage and latency. + * It's recommended to "load once, use many times", to amortize the cost + * Note 2 :`dict` content will be copied internally, so `dict` can be released after loading. + * Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead. + * Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of + * how dictionary content is loaded and interpreted. + */ +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used to decompress next frames. + * The dictionary remains active for decompression of future frames using same DCtx. + * + * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function + * will store the DDict references in a table, and the DDict used for decompression + * will be determined at decompression time, as per the dict ID in the frame. + * The memory for the table is allocated on the first call to refDDict, and can be + * freed with ZSTD_freeDCtx(). + * + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. + * Special: referencing a NULL DDict means "return to no-dictionary mode". + * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) to decompress next frame. + * This is the reverse operation of ZSTD_CCtx_refPrefix(), + * and must use the same prefix as the one used during compression. + * Prefix is **only used once**. Reference is discarded at end of frame. + * End of frame is reached when ZSTD_decompressStream() returns 0. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary + * Note 2 : Prefix buffer is referenced. It **must** outlive decompression. + * Prefix buffer must remain unmodified up to the end of frame, + * reached when ZSTD_decompressStream() returns 0. + * Note 3 : By default, the prefix is treated as raw content (ZSTD_dct_rawContent). + * Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section) + * Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost. + * A full dictionary is more costly, as it requires building tables. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, + const void* prefix, size_t prefixSize); + +/* === Memory management === */ + +/*! ZSTD_sizeof_*() : Requires v1.4.0+ + * These functions give the _current_ memory usage of selected object. + * Note that object memory usage can evolve (increase or decrease) over time. */ +ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); +ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); + +#endif /* ZSTD_H_235446 */ + + +/* ************************************************************************************** + * ADVANCED AND EXPERIMENTAL FUNCTIONS + **************************************************************************************** + * The definitions in the following section are considered experimental. + * They are provided for advanced scenarios. + * They should never be used with a dynamic library, as prototypes may change in the future. + * Use them only in association with static linking. + * ***************************************************************************************/ + +#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZSTDLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE +# else +# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE +# endif +#endif + +/* Deprecation warnings : + * Should these warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. + */ +#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZSTD_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_STATIC_API +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API +# endif +#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ + +/**************************************************************************************** + * experimental API (static linking only) + **************************************************************************************** + * The following symbols and constants + * are not planned to join "stable API" status in the near future. + * They can still change in future versions. + * Some of them are planned to remain in the static_only section indefinitely. + * Some of them might be removed in the future (especially when redundant with existing stable functions) + * ***************************************************************************************/ + +#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ +#define ZSTD_SKIPPABLEHEADERSIZE 8 + +/* compression parameter bounds */ +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX_32 29 +#define ZSTD_CHAINLOG_MAX_64 30 +#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX +#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ +#define ZSTD_STRATEGY_MIN ZSTD_fast +#define ZSTD_STRATEGY_MAX ZSTD_btultra2 + + +#define ZSTD_OVERLAPLOG_MIN 0 +#define ZSTD_OVERLAPLOG_MAX 9 + +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame + * requiring larger than (1< 0: + * If litLength != 0: + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 + * If litLength == 0: + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 + * + * Note: This field is optional. ZSTD_generateSequences() will calculate the value of + * 'rep', but repeat offsets do not necessarily need to be calculated from an external + * sequence provider's perspective. For example, ZSTD_compressSequences() does not + * use this 'rep' field at all (as of now). + */ +} ZSTD_Sequence; + +typedef struct { + unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ + unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ + unsigned hashLog; /**< dispatch table : larger == faster, more memory */ + unsigned searchLog; /**< nb of searches : larger == more compression, slower */ + unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ + unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ + ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ +} ZSTD_compressionParameters; + +typedef struct { + int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ + int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ + int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_parameters; + +typedef enum { + ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ +} ZSTD_dictContentType_e; + +typedef enum { + ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ + ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ +} ZSTD_dictLoadMethod_e; + +typedef enum { + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ + ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. + * Useful to save 4 bytes per generated frame. + * Decoder cannot recognise automatically this format, requiring this instruction. */ +} ZSTD_format_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_refMultipleDDicts */ + ZSTD_rmd_refSingleDDict = 0, + ZSTD_rmd_refMultipleDDicts = 1 +} ZSTD_refMultipleDDicts_e; + +typedef enum { + /* Note: this enum and the behavior it controls are effectively internal + * implementation details of the compressor. They are expected to continue + * to evolve and should be considered only in the context of extremely + * advanced performance tuning. + * + * Zstd currently supports the use of a CDict in three ways: + * + * - The contents of the CDict can be copied into the working context. This + * means that the compression can search both the dictionary and input + * while operating on a single set of internal tables. This makes + * the compression faster per-byte of input. However, the initial copy of + * the CDict's tables incurs a fixed cost at the beginning of the + * compression. For small compressions (< 8 KB), that copy can dominate + * the cost of the compression. + * + * - The CDict's tables can be used in-place. In this model, compression is + * slower per input byte, because the compressor has to search two sets of + * tables. However, this model incurs no start-up cost (as long as the + * working context's tables can be reused). For small inputs, this can be + * faster than copying the CDict's tables. + * + * - The CDict's tables are not used at all, and instead we use the working + * context alone to reload the dictionary and use params based on the source + * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). + * This method is effective when the dictionary sizes are very small relative + * to the input size, and the input size is fairly large to begin with. + * + * Zstd has a simple internal heuristic that selects which strategy to use + * at the beginning of a compression. However, if experimentation shows that + * Zstd is making poor choices, it is possible to override that choice with + * this enum. + */ + ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ + ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ + ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ + ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ +} ZSTD_dictAttachPref_e; + +typedef enum { + ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. + * Negative compression levels will be uncompressed, and positive compression + * levels will be compressed. */ + ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be + * emitted if Huffman compression is not profitable. */ + ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ +} ZSTD_literalCompressionMode_e; + +typedef enum { + /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final + * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable + * or ZSTD_ps_disable allow for a force enable/disable the feature. + */ + ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ + ZSTD_ps_enable = 1, /* Force-enable the feature */ + ZSTD_ps_disable = 2 /* Do not use the feature */ +} ZSTD_paramSwitch_e; + +/*************************************** +* Frame size functions +***************************************/ + +/*! ZSTD_findDecompressedSize() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_decompressBound() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - upper-bound for the decompressed size of all data in all successive frames + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. + * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. + * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. + * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: + * upper-bound = # blocks * min(128 KB, Window_Size) + */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + +typedef enum { + ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ + ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ +} ZSTD_sequenceFormat_e; + +/*! ZSTD_generateSequences() : + * Generate sequences using ZSTD_compress2, given a source buffer. + * + * Each block will end with a dummy sequence + * with offset == 0, matchLength == 0, and litLength == length of last literals. + * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) + * simply acts as a block delimiter. + * + * zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2 + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters + * @return : number of sequences generated + */ + +ZSTDLIB_STATIC_API size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize); + +/*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals + * by merging them into into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters + * @return : number of sequences left after merging + */ +ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); + +/*! ZSTD_compressSequences() : + * Compress an array of ZSTD_Sequence, generated from the original source buffer, into dst. + * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) + * The entire source is compressed into a single frame. + * + * The compression behavior changes based on cctx params. In particular: + * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on + * the block size derived from the cctx, and sequences may be split. This is the default setting. + * + * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. + * + * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined + * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. + * + * In addition to the two adjustable experimental params, there are other important cctx params. + * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. + * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. + * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset + * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md + * + * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. + * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, + * and cannot emit an RLE block that disagrees with the repcode history + * @return : final compressed size or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstSize, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize); + + +/*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * Skippable frames begin with a a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + * + * Returns an error if destination buffer is not large enough, if the source size is not representable + * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant); + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize); + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + */ +ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); + + + +/*************************************** +* Memory management +***************************************/ + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * for any compression level up to selected one. + * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate + * does not include space for a window buffer. + * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * When srcSize can be bound by a known and rather "small" value, + * this fact can be used to provide a tighter estimation + * because the CCtx compression context will need less memory. + * This tighter estimation can be provided by more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note 2 : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimateCStreamSize() : + * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note : CStream size estimation is only correct for single-threaded compression. + * ZSTD_DStream memory budget depends on window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). + * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); + +/*! ZSTD_initStatic*() : + * Initialize an object using a pre-allocated fixed-size buffer. + * workspace: The memory area to emplace the object into. + * Provided pointer *must be 8-bytes aligned*. + * Buffer must outlive object. + * workspaceSize: Use ZSTD_estimate*Size() to determine + * how large workspace must be to support target scenario. + * @return : pointer to object (same address as workspace, just different type), + * or NULL if error (size too small, incorrect alignment, etc.) + * Note : zstd will never resize nor malloc() when using a static buffer. + * If the object requires more memory than available, + * zstd will just error out (typically ZSTD_error_memory_allocation). + * Note 2 : there is no corresponding "free" function. + * Since workspace is allocated externally, it must be freed externally too. + * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level + * into its associated cParams. + * Limitation 1 : currently not compatible with internal dictionary creation, triggered by + * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). + * Limitation 2 : static cctx currently not compatible with multi-threading. + * Limitation 3 : static dctx is incompatible with legacy support. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ + +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ + +ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams); + +ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass your own allocation/free functions. + * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); +typedef void (*ZSTD_freeFunction) (void* opaque, void* address); +typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +/*! Thread pool : + * These prototypes make it possible to share a thread pool among multiple compression contexts. + * This can limit resources for applications with multiple threads where each one uses + * a threaded compression mode (via ZSTD_c_nbWorkers parameter). + * ZSTD_createThreadPool creates a new thread pool with a given number of threads. + * Note that the lifetime of such pool must exist while being used. + * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value + * to use an internal thread pool). + * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. + */ +typedef struct POOL_ctx_s ZSTD_threadPool; +ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); +ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); + + +/* + * This API is temporary and is expected to change or disappear in the future! + */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* cctxParams, + ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + + +/*************************************** +* Advanced compression functions +***************************************/ + +/*! ZSTD_createCDict_byReference() : + * Create a digested dictionary for compression + * Dictionary content is just referenced, not duplicated. + * As a consequence, `dictBuffer` **must** outlive CDict, + * and its content must remain unmodified throughout the lifetime of CDict. + * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. + * `estimatedSrcSize` value is optional, select 0 if not known */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_getParams() : + * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. + * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ +ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_checkCParams() : + * Ensure param values remain within authorized range. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ +ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustCParams() : + * optimize params for a given `srcSize` and `dictSize`. + * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. + * `dictSize` must be `0` when there is no dictionary. + * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. + * This function never fails (wide contract) */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); + +/*! ZSTD_compress_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2") +size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); + +/*! ZSTD_compress_usingCDict_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams); + + +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. + * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_loadDictionary_advanced() : + * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_CCtx_refPrefix_advanced() : + * Same as ZSTD_CCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/* === experimental parameters === */ +/* these parameters can be used with ZSTD_setParameter() + * they are not guaranteed to remain supported in the future */ + + /* Enables rsyncable mode, + * which makes compressed files more rsync friendly + * by adding periodic synchronization points to the compressed data. + * The target average block size is ZSTD_c_jobSize / 2. + * It's possible to modify the job size to increase or decrease + * the granularity of the synchronization point. + * Once the jobSize is smaller than the window size, + * it will result in compression ratio degradation. + * NOTE 1: rsyncable mode only works when multithreading is enabled. + * NOTE 2: rsyncable performs poorly in combination with long range mode, + * since it will decrease the effectiveness of synchronization points, + * though mileage may vary. + * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. + * If the selected compression level is already running significantly slower, + * the overall speed won't be significantly impacted. + */ + #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 + +/* Select a compression format. + * The value must be of type ZSTD_format_e. + * See ZSTD_format_e enum definition for details */ +#define ZSTD_c_format ZSTD_c_experimentalParam2 + +/* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ +#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 + +/* Controls whether the contents of a CDict + * are used in place, or copied into the working context. + * Accepts values from the ZSTD_dictAttachPref_e enum. + * See the comments on that enum for an explanation of the feature. */ +#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 + +/* Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never compress literals. + * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals + * may still be emitted if huffman is not beneficial to use.) + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * literals compression based on the compression parameters - specifically, + * negative compression levels do not use literal compression. + */ +#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 + +/* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size (default:0) */ +#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 + +/* User's best guess of source size. + * Hint is not valid when srcSizeHint == 0. + * There is no guarantee that hint is close to actual source size, + * but compression ratio may regress significantly if guess considerably underestimates */ +#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 + +/* Controls whether the new and experimental "dedicated dictionary search + * structure" can be used. This feature is still rough around the edges, be + * prepared for surprising behavior! + * + * How to use it: + * + * When using a CDict, whether to use this feature or not is controlled at + * CDict creation, and it must be set in a CCtxParams set passed into that + * construction (via ZSTD_createCDict_advanced2()). A compression will then + * use the feature or not based on how the CDict was constructed; the value of + * this param, set in the CCtx, will have no effect. + * + * However, when a dictionary buffer is passed into a CCtx, such as via + * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control + * whether the CDict that is created internally can use the feature or not. + * + * What it does: + * + * Normally, the internal data structures of the CDict are analogous to what + * would be stored in a CCtx after compressing the contents of a dictionary. + * To an approximation, a compression using a dictionary can then use those + * data structures to simply continue what is effectively a streaming + * compression where the simulated compression of the dictionary left off. + * Which is to say, the search structures in the CDict are normally the same + * format as in the CCtx. + * + * It is possible to do better, since the CDict is not like a CCtx: the search + * structures are written once during CDict creation, and then are only read + * after that, while the search structures in the CCtx are both read and + * written as the compression goes along. This means we can choose a search + * structure for the dictionary that is read-optimized. + * + * This feature enables the use of that different structure. + * + * Note that some of the members of the ZSTD_compressionParameters struct have + * different semantics and constraints in the dedicated search structure. It is + * highly recommended that you simply set a compression level in the CCtxParams + * you pass into the CDict creation call, and avoid messing with the cParams + * directly. + * + * Effects: + * + * This will only have any effect when the selected ZSTD_strategy + * implementation supports this feature. Currently, that's limited to + * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. + * + * Note that this means that the CDict tables can no longer be copied into the + * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be + * usable. The dictionary can only be attached or reloaded. + * + * In general, you should expect compression to be faster--sometimes very much + * so--and CDict creation to be slightly slower. Eventually, we will probably + * make this mode the default. + */ +#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 + +/* ZSTD_c_stableInBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the compressor that the ZSTD_inBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the compressor, and + * compression will fail if it ever changes. This means the only flush + * mode that makes sense is ZSTD_e_end, so zstd will error if ZSTD_e_end + * is not used. The data in the ZSTD_inBuffer in the range [src, src + pos) + * MUST not be modified during compression or you will get data corruption. + * + * When this flag is enabled zstd won't allocate an input window buffer, + * because the user guarantees it can reference the ZSTD_inBuffer until + * the frame is complete. But, it will still allocate an output buffer + * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also + * avoid the memcpy() from the input buffer to the input window buffer. + * + * NOTE: ZSTD_compressStream2() will error if ZSTD_e_end is not used. + * That means this flag cannot be used with ZSTD_compressStream(). + * + * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, compression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_inBuffer in the range [dst, dst + pos) MUST + * not be modified during compression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_inBuffer to find + * matches. Normally zstd maintains its own window buffer for this purpose, + * but passing this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 + +/* ZSTD_c_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells he compressor that the ZSTD_outBuffer will not be resized between + * calls. Specifically: (out.size - out.pos) will never grow. This gives the + * compressor the freedom to say: If the compressed data doesn't fit in the + * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to + * always decompress directly into the output buffer, instead of decompressing + * into an internal buffer and copying to the output buffer. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer. It will still allocate the + * input window buffer (see ZSTD_c_stableInBuffer). + * + * Zstd will check that (out.size - out.pos) never grows and return an error + * if it does. While not strictly necessary, this should prevent surprises. + */ +#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 + +/* ZSTD_c_blockDelimiters + * Default is 0 == ZSTD_sf_noBlockDelimiters. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * + * Designates whether or not the given array of ZSTD_Sequence contains block delimiters + * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. + * See the definition of ZSTD_Sequence for more specifics. + */ +#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 + +/* ZSTD_c_validateSequences + * Default is 0 == disabled. Set to 1 to enable sequence validation. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * Designates whether or not we validate sequences provided to ZSTD_compressSequences() + * during function execution. + * + * Without validation, providing a sequence that does not conform to the zstd spec will cause + * undefined behavior, and may produce a corrupted block. + * + * With validation enabled, a if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and + * return an error. + * + */ +#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 + +/* ZSTD_c_useBlockSplitter + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use block splitter. + * Set to ZSTD_ps_enable to always use block splitter. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * block splitting based on the compression parameters. + */ +#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 + +/* ZSTD_c_useRowMatchFinder + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use row-based matchfinder. + * Set to ZSTD_ps_enable to force usage of row-based matchfinder. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * the row-based matchfinder based on support for SIMD instructions and the window log. + * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 + */ +#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 + +/* ZSTD_c_deterministicRefPrefix + * Default is 0 == disabled. Set to 1 to enable. + * + * Zstd produces different results for prefix compression when the prefix is + * directly adjacent to the data about to be compressed vs. when it isn't. + * This is because zstd detects that the two buffers are contiguous and it can + * use a more efficient match finding algorithm. However, this produces different + * results than when the two buffers are non-contiguous. This flag forces zstd + * to always load the prefix in non-contiguous mode, even if it happens to be + * adjacent to the data, to guarantee determinism. + * + * If you really care about determinism when using a dictionary or prefix, + * like when doing delta compression, you should select this option. It comes + * at a speed penalty of about ~2.5% if the dictionary and data happened to be + * contiguous, and is free if they weren't contiguous. We don't expect that + * intentionally making the dictionary and data contiguous will be worth the + * cost to memcpy() the data. + */ +#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 + +/*! ZSTD_CCtx_getParameter() : + * Get the requested compression parameter value, selected by enum ZSTD_cParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); + + +/*! ZSTD_CCtx_params : + * Quick howto : + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into + * an existing ZSTD_CCtx_params structure. + * This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + * an existing CCtx. + * These parameters will be applied to + * all subsequent frames. + * - ZSTD_compressStream2() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. + * + * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + * for static allocation of CCtx for single-threaded compression. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ + +/*! ZSTD_CCtxParams_reset() : + * Reset params to default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_init() : + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_CCtxParams_init_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using + * ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : a code representing success or failure (which can be tested with + * ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtxParams_getParameter() : + * Similar to ZSTD_CCtx_getParameter. + * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); + +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This can be done even after compression is started, + * if nbWorkers==0, this will have no impact until a new compression is started. + * if nbWorkers>=1, new parameters will be picked up at next job, + * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); + +/*! ZSTD_compressStream2_simpleArgs() : + * Same as ZSTD_compressStream2(), + * but using only integral types as arguments. + * This variant might be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + +/*************************************** +* Advanced decompression functions +***************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_byReference() : + * Same as ZSTD_DCtx_loadDictionary(), + * but references `dict` content instead of copying it into `dctx`. + * This saves memory if `dict` remains around., + * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_advanced() : + * Same as ZSTD_DCtx_loadDictionary(), + * but gives direct control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_refPrefix_advanced() : + * Same as ZSTD_DCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_setMaxWindowSize() : + * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + * This protects a decoder context from reserving too much memory for itself (potential attack scenario). + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/*! ZSTD_DCtx_getParameter() : + * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); + +/* ZSTD_d_format + * experimental parameter, + * allowing selection between ZSTD_format_e input compression formats + */ +#define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flags is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/* ZSTD_d_forceIgnoreChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some + * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e + */ +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 + +/* ZSTD_d_refMultipleDDicts + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * If enabled and dctx is allocated on the heap, then additional memory will be allocated + * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() + * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead + * store all references. At decompression time, the appropriate dictID is selected + * from the set of DDicts based on the dictID in the frame. + * + * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. + * + * Param has values of byte ZSTD_refMultipleDDicts_e + * + * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory + * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. + * Memory is allocated as per ZSTD_DCtx::customMem. + * + * Although this function allocates memory for the table, the user is still responsible for + * memory management of the underlying ZSTD_DDict* themselves. + */ +#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 + + +/*! ZSTD_DCtx_setFormat() : + * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). + * Instruct the decoder context about what kind of data to decode next. + * This instruction is mandatory to decode data without a fully-formed header, + * such ZSTD_f_zstd1_magicless for example. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); + +/*! ZSTD_decompressStream_simpleArgs() : + * Same as ZSTD_decompressStream(), + * but using only integral types as arguments. + * This can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + +/******************************************************************** +* Advanced streaming functions +* Warning : most of these functions are now redundant with the Advanced API. +* Once Advanced API reaches "stable" status, +* redundant functions will be deprecated, and then at some point removed. +********************************************************************/ + +/*===== Advanced Streaming compression functions =====*/ + +/*! ZSTD_initCStream_srcSize() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * pledgedSrcSize must be correct. If it is not known at init time, use + * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, + * "0" also disables frame content size field. It may be enabled in the future. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, + int compressionLevel, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingDict() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * Creates of an internal CDict (incompatible with static CCtx), except if + * dict == NULL or dictSize < 8, in which case no dict is used. + * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if + * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + int compressionLevel); + +/*! ZSTD_initCStream_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd parameter and leave the rest as-is. + * for ((param, value) : params) { + * ZSTD_CCtx_setParameter(zcs, param, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. + * pledgedSrcSize must be correct. + * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingCDict() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * note : cdict will just be referenced, and must outlive compression session + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); + +/*! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. + * for ((fParam, value) : fParams) { + * ZSTD_CCtx_setParameter(zcs, fParam, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. + * pledgedSrcSize must be correct. If srcSize is not known at init time, use + * value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize); + +/*! ZSTD_resetCStream() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but + * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be + * explicitly specified. + * + * start a new frame, using same parameters from previous frame. + * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. + * Note that zcs must be init at least once before using ZSTD_resetCStream(). + * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. + * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. + * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, + * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); + + +typedef struct { + unsigned long long ingested; /* nb input bytes read and buffered */ + unsigned long long consumed; /* nb input bytes actually compressed */ + unsigned long long produced; /* nb of compressed bytes generated and buffered */ + unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ + unsigned currentJobID; /* MT only : latest started job nb */ + unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ +} ZSTD_frameProgression; + +/* ZSTD_getFrameProgression() : + * tells how much data has been ingested (read from input) + * consumed (input actually compressed) and produced (output) for current frame. + * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. + * Aggregates progression inside active worker threads. + */ +ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); + +/*! ZSTD_toFlushNow() : + * Tell how many bytes are ready to be flushed immediately. + * Useful for multithreading scenarios (nbWorkers >= 1). + * Probe the oldest active job, defined as oldest job not yet entirely flushed, + * and check its output buffer. + * @return : amount of data stored in oldest job and ready to be flushed immediately. + * if @return == 0, it means either : + * + there is no active job (could be checked with ZSTD_frameProgression()), or + * + oldest job is still actively compressing data, + * but everything it has produced has also been flushed so far, + * therefore flush speed is limited by production speed of oldest job + * irrespective of the speed of concurrent (and newer) jobs. + */ +ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); + + +/*===== Advanced Streaming decompression functions =====*/ + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); + * + * note: no dictionary will be used if dict == NULL or dictSize < 8 + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, ddict); + * + * note : ddict is referenced, it must outlive decompression session + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * + * re-use decompression parameters from previous init; saves dictionary loading + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); + + +/********************************************************************* +* Buffer-less and synchronous inner streaming functions +* +* This is an advanced API, giving full control over buffer management, for users which need direct control over memory. +* But it's also a complex one, with several restrictions, documented below. +* Prefer normal streaming API for an easier experience. +********************************************************************* */ + +/** + Buffer-less streaming compression (synchronous mode) + + A ZSTD_CCtx object is required to track streaming operations. + Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. + ZSTD_CCtx object can be re-used multiple times within successive compression operations. + + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. + It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() + + Then, consume your input using ZSTD_compressContinue(). + There are some important considerations to keep in mind when using this advanced function : + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. + - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. + Worst case evaluation is provided by ZSTD_compressBound(). + ZSTD_compressContinue() doesn't guarantee recover after a failed compression. + - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). + It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) + - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. + In which case, it will "discard" the relevant memory section from its history. + + Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. + It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. + + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again. +*/ + +/*===== Buffer-less streaming compression functions =====*/ +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ +ZSTDLIB_STATIC_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +/** + Buffer-less streaming decompression (synchronous mode) + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be re-used multiple times. + + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. + errorCode, which can be tested using ZSTD_isError(). + + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can @return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). + + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. + + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. + It can also be an error code, which can be tested with ZSTD_isError(). + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. + + Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). + This information is not required to properly decode a frame. + + == Special case : skippable frames == + + Skippable frames allow integration of user-defined data into a flow of concatenated frames. + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : + a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F + b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits + c) Frame Content - any content (User Data) of length equal to Frame Size + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. +*/ + +/*===== Buffer-less streaming decompression functions =====*/ +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; +} ZSTD_frameHeader; + +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; +ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + + + +/* ============================ */ +/** Block level API */ +/* ============================ */ + +/*! + Block functions produce and decode raw zstd blocks, without frame metadata. + Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). + But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. + + A few rules to respect : + - Compressing and decompressing require a context structure + + Use ZSTD_createCCtx() and ZSTD_createDCtx() + - It is necessary to init context before starting + + compression : any ZSTD_compressBegin*() variant, including with dictionary + + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + + copyCCtx() and copyDCtx() can be used too + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + + If input is larger than a block size, it's necessary to split input data into multiple blocks + + For inputs larger than a single block, consider using regular ZSTD_compress() instead. + Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. + - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! + ===> In which case, nothing is produced into `dst` ! + + User __must__ test for such outcome and deal directly with uncompressed data + + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. + Doing so would mess up with statistics history, leading to potential data corruption. + + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! + + In case of multiple successive blocks, should some of them be uncompressed, + decoder must be informed of their existence in order to follow proper history. + Use ZSTD_insertBlock() for such a case. +*/ + +/*===== Raw zstd block functions =====*/ +ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + + +#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/zstd_errors.h b/stage1/zstd/lib/zstd_errors.h new file mode 100644 index 000000000000..fa3686b77243 --- /dev/null +++ b/stage1/zstd/lib/zstd_errors.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_ERRORS_H_398273423 +#define ZSTD_ERRORS_H_398273423 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*===== dependency =====*/ +#include /* size_t */ + + +/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBILITY +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY +#endif + +/*-********************************************* + * Error codes list + *-********************************************* + * Error codes _values_ are pinned down since v1.3.1 only. + * Therefore, don't rely on values if you may link to any version < v1.3.1. + * + * Only values < 100 are considered stable. + * + * note 1 : this API shall be used with static linking only. + * dynamic linking is not yet officially supported. + * note 2 : Prefer relying on the enum than on its value whenever possible + * This is the only supported way to use the error list < v1.3.1 + * note 3 : ZSTD_isError() is always correct, whatever the library version. + **********************************************/ +typedef enum { + ZSTD_error_no_error = 0, + ZSTD_error_GENERIC = 1, + ZSTD_error_prefix_unknown = 10, + ZSTD_error_version_unsupported = 12, + ZSTD_error_frameParameter_unsupported = 14, + ZSTD_error_frameParameter_windowTooLarge = 16, + ZSTD_error_corruption_detected = 20, + ZSTD_error_checksum_wrong = 22, + ZSTD_error_dictionary_corrupted = 30, + ZSTD_error_dictionary_wrong = 32, + ZSTD_error_dictionaryCreation_failed = 34, + ZSTD_error_parameter_unsupported = 40, + ZSTD_error_parameter_outOfBound = 42, + ZSTD_error_tableLog_tooLarge = 44, + ZSTD_error_maxSymbolValue_tooLarge = 46, + ZSTD_error_maxSymbolValue_tooSmall = 48, + ZSTD_error_stage_wrong = 60, + ZSTD_error_init_missing = 62, + ZSTD_error_memory_allocation = 64, + ZSTD_error_workSpace_tooSmall= 66, + ZSTD_error_dstSize_tooSmall = 70, + ZSTD_error_srcSize_wrong = 72, + ZSTD_error_dstBuffer_null = 74, + /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ + ZSTD_error_frameIndex_tooLarge = 100, + ZSTD_error_seekableIO = 102, + ZSTD_error_dstBuffer_wrong = 104, + ZSTD_error_srcBuffer_wrong = 105, + ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ +} ZSTD_ErrorCode; + +/*! ZSTD_getErrorCode() : + convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, + which can be used to compare with enum list published above */ +ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); +ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_ERRORS_H_398273423 */ From fb9a6084e28f3b732dbbce85b0706a70d848c24c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 21:51:33 -0700 Subject: [PATCH 15/68] zig1.c: decompress zig1.wasm.zst with zstd --- CMakeLists.txt | 17 +- stage1/zig1.c | 119 ++-- .../lib/decompress/huf_decompress_amd64.S | 585 ------------------ 3 files changed, 77 insertions(+), 644 deletions(-) delete mode 100644 stage1/zstd/lib/decompress/huf_decompress_amd64.S diff --git a/CMakeLists.txt b/CMakeLists.txt index d48187a90fec..3d495e15c87e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,16 @@ set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") set(STAGE1_SOURCES "${CMAKE_SOURCE_DIR}/stage1/zig1.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/huf_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_ddict.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress_block.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/entropy_common.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/error_private.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/fse_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/pool.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/xxhash.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/zstd_common.c" ) set(ZIG_CPP_SOURCES # These are planned to stay even when we are self-hosted. @@ -710,14 +720,15 @@ endif() add_executable(zig1 ${STAGE1_SOURCES}) set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) target_link_libraries(zig1 LINK_PUBLIC m) - +target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") +target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") set(BUILD_ZIG2_ARGS "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_BINARY_DIR}" zig2 - "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" + "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-exe src/main.zig -ofmt=c -lc -target x86_64-linux-musl # TODO: autodetect in zig1.c -OReleaseFast @@ -736,7 +747,7 @@ set(BUILD_COMPILER_RT_ARGS "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_BINARY_DIR}" compiler_rt - "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm" + "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-obj lib/compiler_rt.zig -ofmt=c -target x86_64-linux-musl # TODO: autodetect in zig1.c -OReleaseFast diff --git a/stage1/zig1.c b/stage1/zig1.c index 34df5230f575..05d4b73947a4 100755 --- a/stage1/zig1.c +++ b/stage1/zig1.c @@ -20,6 +20,8 @@ #include #endif +#include + enum wasi_errno_t { WASI_ESUCCESS = 0, WASI_E2BIG = 1, @@ -4122,7 +4124,12 @@ int main(int argc, char **argv) { new_argv[new_argv_i] = NULL; - const struct ByteSlice mod = read_file_alloc(wasm_file); + const struct ByteSlice compressed_bytes = read_file_alloc(wasm_file); + + const size_t max_uncompressed_size = 2500000; + char *mod_ptr = arena_alloc(max_uncompressed_size); + size_t mod_len = ZSTD_decompress(mod_ptr, max_uncompressed_size, + compressed_bytes.ptr, compressed_bytes.len); int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); @@ -4136,22 +4143,22 @@ int main(int argc, char **argv) { uint32_t i = 0; - if (mod.ptr[0] != 0 || mod.ptr[1] != 'a' || mod.ptr[2] != 's' || mod.ptr[3] != 'm') { + if (mod_ptr[0] != 0 || mod_ptr[1] != 'a' || mod_ptr[2] != 's' || mod_ptr[3] != 'm') { panic("bad magic"); } i += 4; - uint32_t version = read_u32_le(mod.ptr + i); + uint32_t version = read_u32_le(mod_ptr + i); i += 4; if (version != 1) panic("bad wasm version"); uint32_t section_starts[13]; memset(§ion_starts, 0, sizeof(uint32_t) * 13); - while (i < mod.len) { - uint8_t section_id = mod.ptr[i]; + while (i < mod_len) { + uint8_t section_id = mod_ptr[i]; i += 1; - uint32_t section_len = read32_uleb128(mod.ptr, &i); + uint32_t section_len = read32_uleb128(mod_ptr, &i); section_starts[section_id] = i; i += section_len; } @@ -4160,18 +4167,18 @@ int main(int argc, char **argv) { struct TypeInfo *types; { i = section_starts[Section_type]; - uint32_t types_len = read32_uleb128(mod.ptr, &i); + uint32_t types_len = read32_uleb128(mod_ptr, &i); types = arena_alloc(sizeof(struct TypeInfo) * types_len); for (size_t type_i = 0; type_i < types_len; type_i += 1) { struct TypeInfo *info = &types[type_i]; - if (mod.ptr[i] != 0x60) panic("bad type byte"); + if (mod_ptr[i] != 0x60) panic("bad type byte"); i += 1; - info->param_count = read32_uleb128(mod.ptr, &i); + info->param_count = read32_uleb128(mod_ptr, &i); if (info->param_count > 32) panic("found a type with over 32 parameters"); info->param_types = 0; for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { - int64_t param_type = read64_ileb128(mod.ptr, &i); + int64_t param_type = read64_ileb128(mod_ptr, &i); switch (param_type) { case -1: case -3: bs_unset(&info->param_types, param_i); break; case -2: case -4: bs_set(&info->param_types, param_i); break; @@ -4179,10 +4186,10 @@ int main(int argc, char **argv) { } } - info->result_count = read32_uleb128(mod.ptr, &i); + info->result_count = read32_uleb128(mod_ptr, &i); info->result_types = 0; for (uint32_t result_i = 0; result_i < info->result_count; result_i += 1) { - int64_t result_type = read64_ileb128(mod.ptr, &i); + int64_t result_type = read64_ileb128(mod_ptr, &i); switch (result_type) { case -1: case -3: bs_unset(&info->result_types, result_i); break; case -2: case -4: bs_set(&info->result_types, result_i); break; @@ -4197,18 +4204,18 @@ int main(int argc, char **argv) { uint32_t imports_len; { i = section_starts[Section_import]; - imports_len = read32_uleb128(mod.ptr, &i); + imports_len = read32_uleb128(mod_ptr, &i); imports = arena_alloc(sizeof(struct Import) * imports_len); for (size_t imp_i = 0; imp_i < imports_len; imp_i += 1) { struct Import *imp = &imports[imp_i]; - struct ByteSlice mod_name = read_name(mod.ptr, &i); + struct ByteSlice mod_name = read_name(mod_ptr, &i); if (mod_name.len == strlen("wasi_snapshot_preview1") && memcmp(mod_name.ptr, "wasi_snapshot_preview1", mod_name.len) == 0) { imp->mod = ImpMod_wasi_snapshot_preview1; } else panic("unknown import module"); - struct ByteSlice sym_name = read_name(mod.ptr, &i); + struct ByteSlice sym_name = read_name(mod_ptr, &i); if (sym_name.len == strlen("args_get") && memcmp(sym_name.ptr, "args_get", sym_name.len) == 0) { imp->name = ImpName_args_get; @@ -4292,9 +4299,9 @@ int main(int argc, char **argv) { imp->name = ImpName_random_get; } else panic("unknown import name"); - uint32_t desc = read32_uleb128(mod.ptr, &i); + uint32_t desc = read32_uleb128(mod_ptr, &i); if (desc != 0) panic("external kind not function"); - imp->type_idx = read32_uleb128(mod.ptr, &i); + imp->type_idx = read32_uleb128(mod_ptr, &i); } } @@ -4302,11 +4309,11 @@ int main(int argc, char **argv) { uint32_t start_fn_idx; { i = section_starts[Section_export]; - uint32_t count = read32_uleb128(mod.ptr, &i); + uint32_t count = read32_uleb128(mod_ptr, &i); for (; count > 0; count -= 1) { - struct ByteSlice name = read_name(mod.ptr, &i); - uint32_t desc = read32_uleb128(mod.ptr, &i); - start_fn_idx = read32_uleb128(mod.ptr, &i); + struct ByteSlice name = read_name(mod_ptr, &i); + uint32_t desc = read32_uleb128(mod_ptr, &i); + start_fn_idx = read32_uleb128(mod_ptr, &i); if (desc == 0 && name.len == strlen("_start") && memcmp(name.ptr, "_start", name.len) == 0) { @@ -4321,11 +4328,11 @@ int main(int argc, char **argv) { uint32_t functions_len; { i = section_starts[Section_function]; - functions_len = read32_uleb128(mod.ptr, &i); + functions_len = read32_uleb128(mod_ptr, &i); functions = arena_alloc(sizeof(struct Function) * functions_len); for (size_t func_i = 0; func_i < functions_len; func_i += 1) { struct Function *func = &functions[func_i]; - func->type_idx = read32_uleb128(mod.ptr, &i); + func->type_idx = read32_uleb128(mod_ptr, &i); } } @@ -4333,18 +4340,18 @@ int main(int argc, char **argv) { uint64_t *globals; { i = section_starts[Section_global]; - uint32_t globals_len = read32_uleb128(mod.ptr, &i); + uint32_t globals_len = read32_uleb128(mod_ptr, &i); globals = arena_alloc(sizeof(uint64_t) * globals_len); for (size_t glob_i = 0; glob_i < globals_len; glob_i += 1) { uint64_t *global = &globals[glob_i]; - uint32_t content_type = read32_uleb128(mod.ptr, &i); - uint32_t mutability = read32_uleb128(mod.ptr, &i); + uint32_t content_type = read32_uleb128(mod_ptr, &i); + uint32_t mutability = read32_uleb128(mod_ptr, &i); if (mutability != 1) panic("expected mutable global"); if (content_type != 0x7f) panic("unexpected content type"); - uint8_t opcode = mod.ptr[i]; + uint8_t opcode = mod_ptr[i]; i += 1; if (opcode != WasmOp_i32_const) panic("expected i32_const op"); - uint32_t init = read32_ileb128(mod.ptr, &i); + uint32_t init = read32_ileb128(mod_ptr, &i); *global = (uint32_t)init; } } @@ -4353,26 +4360,26 @@ int main(int argc, char **argv) { uint32_t memory_len; { i = section_starts[Section_memory]; - uint32_t memories_len = read32_uleb128(mod.ptr, &i); + uint32_t memories_len = read32_uleb128(mod_ptr, &i); if (memories_len != 1) panic("unexpected memory count"); - uint32_t flags = read32_uleb128(mod.ptr, &i); + uint32_t flags = read32_uleb128(mod_ptr, &i); (void)flags; - memory_len = read32_uleb128(mod.ptr, &i) * wasm_page_size; + memory_len = read32_uleb128(mod_ptr, &i) * wasm_page_size; i = section_starts[Section_data]; - uint32_t datas_count = read32_uleb128(mod.ptr, &i); + uint32_t datas_count = read32_uleb128(mod_ptr, &i); for (; datas_count > 0; datas_count -= 1) { - uint32_t mode = read32_uleb128(mod.ptr, &i); + uint32_t mode = read32_uleb128(mod_ptr, &i); if (mode != 0) panic("expected mode 0"); - enum WasmOp opcode = mod.ptr[i]; + enum WasmOp opcode = mod_ptr[i]; i += 1; if (opcode != WasmOp_i32_const) panic("expected opcode i32_const"); - uint32_t offset = read32_uleb128(mod.ptr, &i); - enum WasmOp end = mod.ptr[i]; + uint32_t offset = read32_uleb128(mod_ptr, &i); + enum WasmOp end = mod_ptr[i]; if (end != WasmOp_end) panic("expected end opcode"); i += 1; - uint32_t bytes_len = read32_uleb128(mod.ptr, &i); - memcpy(memory + offset, mod.ptr + i, bytes_len); + uint32_t bytes_len = read32_uleb128(mod_ptr, &i); + memcpy(memory + offset, mod_ptr + i, bytes_len); i += bytes_len; } } @@ -4380,37 +4387,37 @@ int main(int argc, char **argv) { uint32_t *table = NULL; { i = section_starts[Section_table]; - uint32_t table_count = read32_uleb128(mod.ptr, &i); + uint32_t table_count = read32_uleb128(mod_ptr, &i); if (table_count > 1) { panic("expected only one table section"); } else if (table_count == 1) { - uint32_t element_type = read32_uleb128(mod.ptr, &i); + uint32_t element_type = read32_uleb128(mod_ptr, &i); (void)element_type; - uint32_t has_max = read32_uleb128(mod.ptr, &i); + uint32_t has_max = read32_uleb128(mod_ptr, &i); if (has_max != 1) panic("expected has_max==1"); - uint32_t initial = read32_uleb128(mod.ptr, &i); + uint32_t initial = read32_uleb128(mod_ptr, &i); (void)initial; - uint32_t maximum = read32_uleb128(mod.ptr, &i); + uint32_t maximum = read32_uleb128(mod_ptr, &i); i = section_starts[Section_element]; - uint32_t element_section_count = read32_uleb128(mod.ptr, &i); + uint32_t element_section_count = read32_uleb128(mod_ptr, &i); if (element_section_count != 1) panic("expected one element section"); - uint32_t flags = read32_uleb128(mod.ptr, &i); + uint32_t flags = read32_uleb128(mod_ptr, &i); (void)flags; - enum WasmOp opcode = mod.ptr[i]; + enum WasmOp opcode = mod_ptr[i]; i += 1; if (opcode != WasmOp_i32_const) panic("expected op i32_const"); - uint32_t offset = read32_uleb128(mod.ptr, &i); - enum WasmOp end = mod.ptr[i]; + uint32_t offset = read32_uleb128(mod_ptr, &i); + enum WasmOp end = mod_ptr[i]; if (end != WasmOp_end) panic("expected op end"); i += 1; - uint32_t elem_count = read32_uleb128(mod.ptr, &i); + uint32_t elem_count = read32_uleb128(mod_ptr, &i); table = arena_alloc(sizeof(uint32_t) * maximum); memset(table, 0, sizeof(uint32_t) * maximum); for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { - table[elem_i + offset] = read32_uleb128(mod.ptr, &i); + table[elem_i + offset] = read32_uleb128(mod_ptr, &i); } } } @@ -4420,7 +4427,7 @@ int main(int argc, char **argv) { memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version #endif vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), - vm.mod_ptr = mod.ptr; + vm.mod_ptr = mod_ptr; vm.opcodes = arena_alloc(2000000); vm.operands = arena_alloc(sizeof(uint32_t) * 2000000); vm.stack_top = 0; @@ -4436,14 +4443,14 @@ int main(int argc, char **argv) { { uint32_t code_i = section_starts[Section_code]; - uint32_t codes_len = read32_uleb128(mod.ptr, &code_i); + uint32_t codes_len = read32_uleb128(mod_ptr, &code_i); if (codes_len != functions_len) panic("code/function length mismatch"); struct ProgramCounter pc; pc.opcode = 0; pc.operand = 0; for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) { struct Function *func = &functions[func_i]; - uint32_t size = read32_uleb128(mod.ptr, &code_i); + uint32_t size = read32_uleb128(mod_ptr, &code_i); uint32_t code_begin = code_i; struct TypeInfo *type_info = &vm.types[func->type_idx]; @@ -4451,11 +4458,11 @@ int main(int argc, char **argv) { func->local_types = malloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); func->local_types[0] = type_info->param_types; - for (uint32_t local_sets_count = read32_uleb128(mod.ptr, &code_i); + for (uint32_t local_sets_count = read32_uleb128(mod_ptr, &code_i); local_sets_count > 0; local_sets_count -= 1) { - uint32_t set_count = read32_uleb128(mod.ptr, &code_i); - int64_t local_type = read64_ileb128(mod.ptr, &code_i); + uint32_t set_count = read32_uleb128(mod_ptr, &code_i); + int64_t local_type = read64_ileb128(mod_ptr, &code_i); uint32_t i = type_info->param_count + func->locals_count; func->locals_count += set_count; diff --git a/stage1/zstd/lib/decompress/huf_decompress_amd64.S b/stage1/zstd/lib/decompress/huf_decompress_amd64.S deleted file mode 100644 index 49589cb61141..000000000000 --- a/stage1/zstd/lib/decompress/huf_decompress_amd64.S +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#include "../common/portability_macros.h" - -/* Stack marking - * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart - */ -#if defined(__ELF__) && defined(__GNUC__) -.section .note.GNU-stack,"",%progbits -#endif - -#if ZSTD_ENABLE_ASM_X86_64_BMI2 - -/* Calling convention: - * - * %rdi contains the first argument: HUF_DecompressAsmArgs*. - * %rbp isn't maintained (no frame pointer). - * %rsp contains the stack pointer that grows down. - * No red-zone is assumed, only addresses >= %rsp are used. - * All register contents are preserved. - * - * TODO: Support Windows calling convention. - */ - -ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) -ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) -.global HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop -.global HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop -.global _HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop -.global _HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop -.text - -/* Sets up register mappings for clarity. - * op[], bits[], dtable & ip[0] each get their own register. - * ip[1,2,3] & olimit alias var[]. - * %rax is a scratch register. - */ - -#define op0 rsi -#define op1 rbx -#define op2 rcx -#define op3 rdi - -#define ip0 r8 -#define ip1 r9 -#define ip2 r10 -#define ip3 r11 - -#define bits0 rbp -#define bits1 rdx -#define bits2 r12 -#define bits3 r13 -#define dtable r14 -#define olimit r15 - -/* var[] aliases ip[1,2,3] & olimit - * ip[1,2,3] are saved every iteration. - * olimit is only used in compute_olimit. - */ -#define var0 r15 -#define var1 r9 -#define var2 r10 -#define var3 r11 - -/* 32-bit var registers */ -#define vard0 r15d -#define vard1 r9d -#define vard2 r10d -#define vard3 r11d - -/* Calls X(N) for each stream 0, 1, 2, 3. */ -#define FOR_EACH_STREAM(X) \ - X(0); \ - X(1); \ - X(2); \ - X(3) - -/* Calls X(N, idx) for each stream 0, 1, 2, 3. */ -#define FOR_EACH_STREAM_WITH_INDEX(X, idx) \ - X(0, idx); \ - X(1, idx); \ - X(2, idx); \ - X(3, idx) - -/* Define both _HUF_* & HUF_* symbols because MacOS - * C symbols are prefixed with '_' & Linux symbols aren't. - */ -_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: -HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: - /* Save all registers - even if they are callee saved for simplicity. */ - push %rax - push %rbx - push %rcx - push %rdx - push %rbp - push %rsi - push %rdi - push %r8 - push %r9 - push %r10 - push %r11 - push %r12 - push %r13 - push %r14 - push %r15 - - /* Read HUF_DecompressAsmArgs* args from %rax */ - movq %rdi, %rax - movq 0(%rax), %ip0 - movq 8(%rax), %ip1 - movq 16(%rax), %ip2 - movq 24(%rax), %ip3 - movq 32(%rax), %op0 - movq 40(%rax), %op1 - movq 48(%rax), %op2 - movq 56(%rax), %op3 - movq 64(%rax), %bits0 - movq 72(%rax), %bits1 - movq 80(%rax), %bits2 - movq 88(%rax), %bits3 - movq 96(%rax), %dtable - push %rax /* argument */ - push 104(%rax) /* ilimit */ - push 112(%rax) /* oend */ - push %olimit /* olimit space */ - - subq $24, %rsp - -.L_4X1_compute_olimit: - /* Computes how many iterations we can do safely - * %r15, %rax may be clobbered - * rbx, rdx must be saved - * op3 & ip0 mustn't be clobbered - */ - movq %rbx, 0(%rsp) - movq %rdx, 8(%rsp) - - movq 32(%rsp), %rax /* rax = oend */ - subq %op3, %rax /* rax = oend - op3 */ - - /* r15 = (oend - op3) / 5 */ - movabsq $-3689348814741910323, %rdx - mulq %rdx - movq %rdx, %r15 - shrq $2, %r15 - - movq %ip0, %rax /* rax = ip0 */ - movq 40(%rsp), %rdx /* rdx = ilimit */ - subq %rdx, %rax /* rax = ip0 - ilimit */ - movq %rax, %rbx /* rbx = ip0 - ilimit */ - - /* rdx = (ip0 - ilimit) / 7 */ - movabsq $2635249153387078803, %rdx - mulq %rdx - subq %rdx, %rbx - shrq %rbx - addq %rbx, %rdx - shrq $2, %rdx - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - /* r15 = r15 * 5 */ - leaq (%r15, %r15, 4), %r15 - - /* olimit = op3 + r15 */ - addq %op3, %olimit - - movq 8(%rsp), %rdx - movq 0(%rsp), %rbx - - /* If (op3 + 20 > olimit) */ - movq %op3, %rax /* rax = op3 */ - addq $20, %rax /* rax = op3 + 20 */ - cmpq %rax, %olimit /* op3 + 20 > olimit */ - jb .L_4X1_exit - - /* If (ip1 < ip0) go to exit */ - cmpq %ip0, %ip1 - jb .L_4X1_exit - - /* If (ip2 < ip1) go to exit */ - cmpq %ip1, %ip2 - jb .L_4X1_exit - - /* If (ip3 < ip2) go to exit */ - cmpq %ip2, %ip3 - jb .L_4X1_exit - -/* Reads top 11 bits from bits[n] - * Loads dt[bits[n]] into var[n] - */ -#define GET_NEXT_DELT(n) \ - movq $53, %var##n; \ - shrxq %var##n, %bits##n, %var##n; \ - movzwl (%dtable,%var##n,2),%vard##n - -/* var[n] must contain the DTable entry computed with GET_NEXT_DELT - * Moves var[n] to %rax - * bits[n] <<= var[n] & 63 - * op[n][idx] = %rax >> 8 - * %ah is a way to access bits [8, 16) of %rax - */ -#define DECODE_FROM_DELT(n, idx) \ - movq %var##n, %rax; \ - shlxq %var##n, %bits##n, %bits##n; \ - movb %ah, idx(%op##n) - -/* Assumes GET_NEXT_DELT has been called. - * Calls DECODE_FROM_DELT then GET_NEXT_DELT - */ -#define DECODE_AND_GET_NEXT(n, idx) \ - DECODE_FROM_DELT(n, idx); \ - GET_NEXT_DELT(n) \ - -/* // ctz & nbBytes is stored in bits[n] - * // nbBits is stored in %rax - * ctz = CTZ[bits[n]] - * nbBits = ctz & 7 - * nbBytes = ctz >> 3 - * op[n] += 5 - * ip[n] -= nbBytes - * // Note: x86-64 is little-endian ==> no bswap - * bits[n] = MEM_readST(ip[n]) | 1 - * bits[n] <<= nbBits - */ -#define RELOAD_BITS(n) \ - bsfq %bits##n, %bits##n; \ - movq %bits##n, %rax; \ - andq $7, %rax; \ - shrq $3, %bits##n; \ - leaq 5(%op##n), %op##n; \ - subq %bits##n, %ip##n; \ - movq (%ip##n), %bits##n; \ - orq $1, %bits##n; \ - shlx %rax, %bits##n, %bits##n - - /* Store clobbered variables on the stack */ - movq %olimit, 24(%rsp) - movq %ip1, 0(%rsp) - movq %ip2, 8(%rsp) - movq %ip3, 16(%rsp) - - /* Call GET_NEXT_DELT for each stream */ - FOR_EACH_STREAM(GET_NEXT_DELT) - - .p2align 6 - -.L_4X1_loop_body: - /* Decode 5 symbols in each of the 4 streams (20 total) - * Must have called GET_NEXT_DELT for each stream - */ - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 0) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 1) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 2) - FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 3) - FOR_EACH_STREAM_WITH_INDEX(DECODE_FROM_DELT, 4) - - /* Load ip[1,2,3] from stack (var[] aliases them) - * ip[] is needed for RELOAD_BITS - * Each will be stored back to the stack after RELOAD - */ - movq 0(%rsp), %ip1 - movq 8(%rsp), %ip2 - movq 16(%rsp), %ip3 - - /* Reload each stream & fetch the next table entry - * to prepare for the next iteration - */ - RELOAD_BITS(0) - GET_NEXT_DELT(0) - - RELOAD_BITS(1) - movq %ip1, 0(%rsp) - GET_NEXT_DELT(1) - - RELOAD_BITS(2) - movq %ip2, 8(%rsp) - GET_NEXT_DELT(2) - - RELOAD_BITS(3) - movq %ip3, 16(%rsp) - GET_NEXT_DELT(3) - - /* If op3 < olimit: continue the loop */ - cmp %op3, 24(%rsp) - ja .L_4X1_loop_body - - /* Reload ip[1,2,3] from stack */ - movq 0(%rsp), %ip1 - movq 8(%rsp), %ip2 - movq 16(%rsp), %ip3 - - /* Re-compute olimit */ - jmp .L_4X1_compute_olimit - -#undef GET_NEXT_DELT -#undef DECODE_FROM_DELT -#undef DECODE -#undef RELOAD_BITS -.L_4X1_exit: - addq $24, %rsp - - /* Restore stack (oend & olimit) */ - pop %rax /* olimit */ - pop %rax /* oend */ - pop %rax /* ilimit */ - pop %rax /* arg */ - - /* Save ip / op / bits */ - movq %ip0, 0(%rax) - movq %ip1, 8(%rax) - movq %ip2, 16(%rax) - movq %ip3, 24(%rax) - movq %op0, 32(%rax) - movq %op1, 40(%rax) - movq %op2, 48(%rax) - movq %op3, 56(%rax) - movq %bits0, 64(%rax) - movq %bits1, 72(%rax) - movq %bits2, 80(%rax) - movq %bits3, 88(%rax) - - /* Restore registers */ - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %r11 - pop %r10 - pop %r9 - pop %r8 - pop %rdi - pop %rsi - pop %rbp - pop %rdx - pop %rcx - pop %rbx - pop %rax - ret - -_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: -HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: - /* Save all registers - even if they are callee saved for simplicity. */ - push %rax - push %rbx - push %rcx - push %rdx - push %rbp - push %rsi - push %rdi - push %r8 - push %r9 - push %r10 - push %r11 - push %r12 - push %r13 - push %r14 - push %r15 - - movq %rdi, %rax - movq 0(%rax), %ip0 - movq 8(%rax), %ip1 - movq 16(%rax), %ip2 - movq 24(%rax), %ip3 - movq 32(%rax), %op0 - movq 40(%rax), %op1 - movq 48(%rax), %op2 - movq 56(%rax), %op3 - movq 64(%rax), %bits0 - movq 72(%rax), %bits1 - movq 80(%rax), %bits2 - movq 88(%rax), %bits3 - movq 96(%rax), %dtable - push %rax /* argument */ - push %rax /* olimit */ - push 104(%rax) /* ilimit */ - - movq 112(%rax), %rax - push %rax /* oend3 */ - - movq %op3, %rax - push %rax /* oend2 */ - - movq %op2, %rax - push %rax /* oend1 */ - - movq %op1, %rax - push %rax /* oend0 */ - - /* Scratch space */ - subq $8, %rsp - -.L_4X2_compute_olimit: - /* Computes how many iterations we can do safely - * %r15, %rax may be clobbered - * rdx must be saved - * op[1,2,3,4] & ip0 mustn't be clobbered - */ - movq %rdx, 0(%rsp) - - /* We can consume up to 7 input bytes each iteration. */ - movq %ip0, %rax /* rax = ip0 */ - movq 40(%rsp), %rdx /* rdx = ilimit */ - subq %rdx, %rax /* rax = ip0 - ilimit */ - movq %rax, %r15 /* r15 = ip0 - ilimit */ - - /* rdx = rax / 7 */ - movabsq $2635249153387078803, %rdx - mulq %rdx - subq %rdx, %r15 - shrq %r15 - addq %r15, %rdx - shrq $2, %rdx - - /* r15 = (ip0 - ilimit) / 7 */ - movq %rdx, %r15 - - movabsq $-3689348814741910323, %rdx - movq 8(%rsp), %rax /* rax = oend0 */ - subq %op0, %rax /* rax = oend0 - op0 */ - mulq %rdx - shrq $3, %rdx /* rdx = rax / 10 */ - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - movabsq $-3689348814741910323, %rdx - movq 16(%rsp), %rax /* rax = oend1 */ - subq %op1, %rax /* rax = oend1 - op1 */ - mulq %rdx - shrq $3, %rdx /* rdx = rax / 10 */ - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - movabsq $-3689348814741910323, %rdx - movq 24(%rsp), %rax /* rax = oend2 */ - subq %op2, %rax /* rax = oend2 - op2 */ - mulq %rdx - shrq $3, %rdx /* rdx = rax / 10 */ - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - movabsq $-3689348814741910323, %rdx - movq 32(%rsp), %rax /* rax = oend3 */ - subq %op3, %rax /* rax = oend3 - op3 */ - mulq %rdx - shrq $3, %rdx /* rdx = rax / 10 */ - - /* r15 = min(%rdx, %r15) */ - cmpq %rdx, %r15 - cmova %rdx, %r15 - - /* olimit = op3 + 5 * r15 */ - movq %r15, %rax - leaq (%op3, %rax, 4), %olimit - addq %rax, %olimit - - movq 0(%rsp), %rdx - - /* If (op3 + 10 > olimit) */ - movq %op3, %rax /* rax = op3 */ - addq $10, %rax /* rax = op3 + 10 */ - cmpq %rax, %olimit /* op3 + 10 > olimit */ - jb .L_4X2_exit - - /* If (ip1 < ip0) go to exit */ - cmpq %ip0, %ip1 - jb .L_4X2_exit - - /* If (ip2 < ip1) go to exit */ - cmpq %ip1, %ip2 - jb .L_4X2_exit - - /* If (ip3 < ip2) go to exit */ - cmpq %ip2, %ip3 - jb .L_4X2_exit - -#define DECODE(n, idx) \ - movq %bits##n, %rax; \ - shrq $53, %rax; \ - movzwl 0(%dtable,%rax,4),%r8d; \ - movzbl 2(%dtable,%rax,4),%r15d; \ - movzbl 3(%dtable,%rax,4),%eax; \ - movw %r8w, (%op##n); \ - shlxq %r15, %bits##n, %bits##n; \ - addq %rax, %op##n - -#define RELOAD_BITS(n) \ - bsfq %bits##n, %bits##n; \ - movq %bits##n, %rax; \ - shrq $3, %bits##n; \ - andq $7, %rax; \ - subq %bits##n, %ip##n; \ - movq (%ip##n), %bits##n; \ - orq $1, %bits##n; \ - shlxq %rax, %bits##n, %bits##n - - - movq %olimit, 48(%rsp) - - .p2align 6 - -.L_4X2_loop_body: - /* We clobber r8, so store it on the stack */ - movq %r8, 0(%rsp) - - /* Decode 5 symbols from each of the 4 streams (20 symbols total). */ - FOR_EACH_STREAM_WITH_INDEX(DECODE, 0) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 1) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 2) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 3) - FOR_EACH_STREAM_WITH_INDEX(DECODE, 4) - - /* Reload r8 */ - movq 0(%rsp), %r8 - - FOR_EACH_STREAM(RELOAD_BITS) - - cmp %op3, 48(%rsp) - ja .L_4X2_loop_body - jmp .L_4X2_compute_olimit - -#undef DECODE -#undef RELOAD_BITS -.L_4X2_exit: - addq $8, %rsp - /* Restore stack (oend & olimit) */ - pop %rax /* oend0 */ - pop %rax /* oend1 */ - pop %rax /* oend2 */ - pop %rax /* oend3 */ - pop %rax /* ilimit */ - pop %rax /* olimit */ - pop %rax /* arg */ - - /* Save ip / op / bits */ - movq %ip0, 0(%rax) - movq %ip1, 8(%rax) - movq %ip2, 16(%rax) - movq %ip3, 24(%rax) - movq %op0, 32(%rax) - movq %op1, 40(%rax) - movq %op2, 48(%rax) - movq %op3, 56(%rax) - movq %bits0, 64(%rax) - movq %bits1, 72(%rax) - movq %bits2, 80(%rax) - movq %bits3, 88(%rax) - - /* Restore registers */ - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %r11 - pop %r10 - pop %r9 - pop %r8 - pop %rdi - pop %rsi - pop %rbp - pop %rdx - pop %rcx - pop %rbx - pop %rax - ret - -#endif From 34e9bbb9d46babecb8c8e5d694b934186654982b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 23:04:18 -0700 Subject: [PATCH 16/68] enable the LLVM backend in stage2 This takes a bit longer since the interpreted part has to do more work but it saves a round trip through the compiler by allowing `zig2 build` to be the final step. 1-2-3, done. For me this is currently failing due to compilation errors generated by GCC when compiling zig2.c but in theory if those are fixed, it should work! --- CMakeLists.txt | 76 +++++++++++++++++++++++++++++++++++++++++++- stage1/config.zig.in | 4 +-- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d495e15c87e..fbfdc118aff9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,7 @@ set(ZIG_CPP_SOURCES ) # Needed because we use cmake, not the zig build system, to build zig2.o. set(ZIG_STAGE2_SOURCES + "${ZIG_CONFIG_ZIG_OUT}" "${CMAKE_SOURCE_DIR}/lib/std/array_hash_map.zig" "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig" "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig" @@ -761,10 +762,83 @@ add_custom_command( WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) - add_executable(zig2 ${ZIG2_C_SOURCE} ${ZIG_COMPILER_RT_C_SOURCE}) set_target_properties(zig2 PROPERTIES COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS} LINK_FLAGS ${ZIG2_LINK_FLAGS} ) target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib") +target_link_libraries(zig2 LINK_PUBLIC zigcpp) + +if(MSVC) + target_link_libraries(zig2 ntdll.lib) +elseif(MINGW) + target_link_libraries(zig2 ntdll) +endif() + +if(NOT MSVC) + target_link_libraries(zig2 LINK_PUBLIC ${LIBXML2}) +endif() + +if(ZIG_DIA_GUIDS_LIB) + target_link_libraries(zig2 LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) +endif() + +if(MSVC OR MINGW) + target_link_libraries(zig2 LINK_PUBLIC version) +endif() + +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(ZIG_RELEASE_ARG "") +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") + set(ZIG_RELEASE_ARG -Drelease) +else() + set(ZIG_RELEASE_ARG -Drelease -Dstrip) +endif() +if(ZIG_NO_LIB) + set(ZIG_NO_LIB_ARG "-Dno-lib") +else() + set(ZIG_NO_LIB_ARG "") +endif() +if(ZIG_SINGLE_THREADED) + set(ZIG_SINGLE_THREADED_ARG "-fsingle-threaded") +else() + set(ZIG_SINGLE_THREADED_ARG "") +endif() +if(ZIG_STATIC) + set(ZIG_STATIC_ARG "-Duse-zig-libcxx") +else() + set(ZIG_STATIC_ARG "") +endif() + +set(ZIG_BUILD_ARGS + --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" + "-Dconfig_h=${ZIG_CONFIG_H_OUT}" + "-Denable-llvm" + ${ZIG_RELEASE_ARG} + ${ZIG_STATIC_ARG} + ${ZIG_NO_LIB_ARG} + ${ZIG_SINGLE_THREADED_ARG} + "-Dtarget=${ZIG_TARGET_TRIPLE}" + "-Dcpu=${ZIG_TARGET_MCPU}" + "-Dversion-string=${RESOLVED_ZIG_VERSION}" +) + +add_custom_target(stage3 ALL + COMMAND zig2 build compile ${ZIG_BUILD_ARGS} + DEPENDS zig2 + COMMENT STATUS "Building stage3" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) + +if(WIN32) + set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2.exe") +else() + set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2") +endif() + +install(CODE "set(ZIG_EXECUTABLE \"${ZIG_EXECUTABLE}\")") +install(CODE "set(ZIG_BUILD_ARGS \"${ZIG_BUILD_ARGS}\")") +install(CODE "set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")") +install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")") +install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/install.cmake") diff --git a/stage1/config.zig.in b/stage1/config.zig.in index 347c757f9385..68d09f159b99 100644 --- a/stage1/config.zig.in +++ b/stage1/config.zig.in @@ -1,4 +1,4 @@ -pub const have_llvm = false; +pub const have_llvm = true; pub const llvm_has_m68k = false; pub const llvm_has_csky = false; pub const llvm_has_arc = false; @@ -10,5 +10,5 @@ pub const enable_tracy = false; pub const value_tracing = false; pub const have_stage1 = false; pub const skip_non_native = false; -pub const only_c = true; +pub const only_c = false; pub const force_gpa = false; From 33e3db11fece0a60b226f5d301657ce4294e4ab5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Nov 2022 23:19:24 -0700 Subject: [PATCH 17/68] zig1.c: autodetect host target triple instead of assuming x8_64-linux in CMake --- CMakeLists.txt | 2 -- stage1/zig1.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbfdc118aff9..935b39da80b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -731,7 +731,6 @@ set(BUILD_ZIG2_ARGS zig2 "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-exe src/main.zig -ofmt=c -lc - -target x86_64-linux-musl # TODO: autodetect in zig1.c -OReleaseFast ) @@ -750,7 +749,6 @@ set(BUILD_COMPILER_RT_ARGS compiler_rt "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-obj lib/compiler_rt.zig -ofmt=c - -target x86_64-linux-musl # TODO: autodetect in zig1.c -OReleaseFast ) diff --git a/stage1/zig1.c b/stage1/zig1.c index 05d4b73947a4..1f99d3edb8ca 100755 --- a/stage1/zig1.c +++ b/stage1/zig1.c @@ -22,6 +22,38 @@ #include +#if defined(__APPLE__) +#define ZIG_TRIPLE_OS "macos" +#elif defined(_WIN32) +#define ZIG_TRIPLE_OS "windows" +#elif defined(__linux__) +#define ZIG_TRIPLE_OS "linux" +#elif defined(__FreeBSD__) +#define ZIG_TRIPLE_OS "freebsd" +#elif defined(__NetBSD__) +#define ZIG_TRIPLE_OS "netbsd" +#elif defined(__DragonFly__) +#define ZIG_TRIPLE_OS "dragonfly" +#elif defined(__OpenBSD__) +#define ZIG_TRIPLE_OS "openbsd" +#elif defined(__HAIKU__) +#define ZIG_TRIPLE_OS "haiku" +#elif defined(__sun) +#define ZIG_TRIPLE_OS "solaris" +#else +#error please add more os definitions above this line +#endif + +#if defined(__x86_64__) +#define ZIG_TRIPLE_ARCH "x86_64" +#elif defined(__aarch64__) +#define ZIG_TRIPLE_ARCH "aarch64" +#elif defined(__ARM_EABI__) +#define ZIG_TRIPLE_ARCH "arm" +#else +#error please add more arch definitions above this line +#endif + enum wasi_errno_t { WASI_ESUCCESS = 0, WASI_E2BIG = 1, @@ -4114,6 +4146,14 @@ int main(int argc, char **argv) { new_argv_i += 1; } + { + new_argv[new_argv_i] = "-target"; + new_argv_i += 1; + + new_argv[new_argv_i] = ZIG_TRIPLE_ARCH "-" ZIG_TRIPLE_OS; + new_argv_i += 1; + } + if (isatty(STDERR_FILENO) != 0) { new_argv[new_argv_i] = "--color"; new_argv_i += 1; From eef780ebf2299181ec182470aa057d77a065ff13 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 17 Nov 2022 00:57:05 -0700 Subject: [PATCH 18/68] CMake: use -O1 instead of -O2 for building generated .c code Idea here is that this is a sweet spot of not wasting time waiting for optimizations but also getting decent runime performance. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 935b39da80b5..f8b242698422 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -713,8 +713,8 @@ if(MSVC) set(ZIG2_COMPILE_FLAGS "/std:c99") set(ZIG2_LINK_FLAGS "/STACK:16777216") else() - set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O2 -march=native") + set(ZIG1_COMPILE_FLAGS "-std=c99 -O1 -march=native") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O1 -march=native") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() From e9d9be2902e63a389531f2ce2197766398c281d6 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Fri, 18 Nov 2022 17:56:15 -0800 Subject: [PATCH 19/68] Some fixes for the wasi interpreter for macOS (#13587) * Remove usage of O_PATH, ifdef for macos stat struct, and integer formatting --- CMakeLists.txt | 4 ++-- stage1/zig1.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f8b242698422..4ebc876305cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -713,8 +713,8 @@ if(MSVC) set(ZIG2_COMPILE_FLAGS "/std:c99") set(ZIG2_LINK_FLAGS "/STACK:16777216") else() - set(ZIG1_COMPILE_FLAGS "-std=c99 -O1 -march=native") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O1 -march=native") + set(ZIG1_COMPILE_FLAGS "-std=c99 -O1") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O1") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() diff --git a/stage1/zig1.c b/stage1/zig1.c index 1f99d3edb8ca..b7d35fd57dd5 100755 --- a/stage1/zig1.c +++ b/stage1/zig1.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -859,9 +860,16 @@ static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm, write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode)); write_u64_le(vm->memory + buf + 0x18, 1); // nlink write_u64_le(vm->memory + buf + 0x20, st.st_size); +#if defined(__APPLE__) + write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atimespec)); + write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtimespec)); + write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctimespec)); +#else write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim)); write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim)); write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim)); +#endif + return WASI_ESUCCESS; } @@ -1173,7 +1181,7 @@ static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, ///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { - fprintf(stderr, "wasi_debug: '%s' number=%lu %lx\n", vm->memory + text, n, n); + fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64" %" PRIx64 "\n", vm->memory + text, n, n); } /// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; @@ -4082,7 +4090,7 @@ int main(int argc, char **argv) { mkdir(cache_dir_buf, 0777); cache_dir = err_wrap("opening cache dir", - open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC)); } // Construct a new argv for the WASI code which has absolute paths @@ -4171,8 +4179,8 @@ int main(int argc, char **argv) { size_t mod_len = ZSTD_decompress(mod_ptr, max_uncompressed_size, compressed_bytes.ptr, compressed_bytes.len); - int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); - int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); + int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC)); + int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC)); add_preopen(0, "stdin", STDIN_FILENO); add_preopen(1, "stdout", STDOUT_FILENO); From 6337808e65fd274fa15acf9df051136661cba515 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Nov 2022 16:36:23 -0700 Subject: [PATCH 20/68] update zig1.c to latest zig-wasi --- stage1/zig1.c | 3645 +++++++++++++++++++++++++------------------------ 1 file changed, 1837 insertions(+), 1808 deletions(-) diff --git a/stage1/zig1.c b/stage1/zig1.c index b7d35fd57dd5..bc65179992b4 100755 --- a/stage1/zig1.c +++ b/stage1/zig1.c @@ -223,7 +223,7 @@ static struct ByteSlice read_file_alloc(const char *file_path) { struct Preopen { - int wasi_fd; + int wasi_fd; int host_fd; const char *name; size_t name_len; @@ -259,10 +259,6 @@ static uint16_t read_u16_le(const char *ptr) { (((uint64_t)u8_ptr[1]) << 0x08); } -static int16_t read_i16_le(const char *ptr) { - return read_u16_le(ptr); -} - static uint32_t read_u32_le(const char *ptr) { const uint8_t *u8_ptr = (const uint8_t *)ptr; return @@ -272,10 +268,6 @@ static uint32_t read_u32_le(const char *ptr) { (((uint64_t)u8_ptr[3]) << 0x18); } -static uint32_t read_i32_le(const char *ptr) { - return read_u32_le(ptr); -} - static uint64_t read_u64_le(const char *ptr) { const uint8_t *u8_ptr = (const uint8_t *)ptr; return @@ -383,19 +375,21 @@ enum Op { Op_br_void, Op_br_32, Op_br_64, - Op_br_if_nez_void, - Op_br_if_nez_32, - Op_br_if_nez_64, - Op_br_if_eqz_void, - Op_br_if_eqz_32, - Op_br_if_eqz_64, + Op_br_nez_void, + Op_br_nez_32, + Op_br_nez_64, + Op_br_eqz_void, + Op_br_eqz_32, + Op_br_eqz_64, Op_br_table_void, Op_br_table_32, Op_br_table_64, Op_return_void, Op_return_32, Op_return_64, - Op_call, + Op_call_import, + Op_call_func, + Op_call_indirect, Op_drop_32, Op_drop_64, Op_select_32, @@ -410,12 +404,160 @@ enum Op { Op_global_get_32, Op_global_set_0_32, Op_global_set_32, + Op_load_0_8, + Op_load_8, + Op_load_0_16, + Op_load_16, + Op_load_0_32, + Op_load_32, + Op_load_0_64, + Op_load_64, + Op_store_0_8, + Op_store_8, + Op_store_0_16, + Op_store_16, + Op_store_0_32, + Op_store_32, + Op_store_0_64, + Op_store_64, + Op_mem_size, + Op_mem_grow, + Op_const_0_32, + Op_const_0_64, + Op_const_1_32, + Op_const_1_64, Op_const_32, Op_const_64, + Op_const_umax_32, + Op_const_umax_64, + Op_eqz_32, + Op_eq_32, + Op_ne_32, + Op_slt_32, + Op_ult_32, + Op_sgt_32, + Op_ugt_32, + Op_sle_32, + Op_ule_32, + Op_sge_32, + Op_uge_32, + Op_eqz_64, + Op_eq_64, + Op_ne_64, + Op_slt_64, + Op_ult_64, + Op_sgt_64, + Op_ugt_64, + Op_sle_64, + Op_ule_64, + Op_sge_64, + Op_uge_64, + Op_feq_32, + Op_fne_32, + Op_flt_32, + Op_fgt_32, + Op_fle_32, + Op_fge_32, + Op_feq_64, + Op_fne_64, + Op_flt_64, + Op_fgt_64, + Op_fle_64, + Op_fge_64, + Op_clz_32, + Op_ctz_32, + Op_popcnt_32, Op_add_32, + Op_sub_32, + Op_mul_32, + Op_sdiv_32, + Op_udiv_32, + Op_srem_32, + Op_urem_32, Op_and_32, - Op_wasm, - Op_wasm_prefixed, + Op_or_32, + Op_xor_32, + Op_shl_32, + Op_ashr_32, + Op_lshr_32, + Op_rol_32, + Op_ror_32, + Op_clz_64, + Op_ctz_64, + Op_popcnt_64, + Op_add_64, + Op_sub_64, + Op_mul_64, + Op_sdiv_64, + Op_udiv_64, + Op_srem_64, + Op_urem_64, + Op_and_64, + Op_or_64, + Op_xor_64, + Op_shl_64, + Op_ashr_64, + Op_lshr_64, + Op_rol_64, + Op_ror_64, + Op_fabs_32, + Op_fneg_32, + Op_ceil_32, + Op_floor_32, + Op_trunc_32, + Op_nearest_32, + Op_sqrt_32, + Op_fadd_32, + Op_fsub_32, + Op_fmul_32, + Op_fdiv_32, + Op_fmin_32, + Op_fmax_32, + Op_copysign_32, + Op_fabs_64, + Op_fneg_64, + Op_ceil_64, + Op_floor_64, + Op_trunc_64, + Op_nearest_64, + Op_sqrt_64, + Op_fadd_64, + Op_fsub_64, + Op_fmul_64, + Op_fdiv_64, + Op_fmin_64, + Op_fmax_64, + Op_copysign_64, + Op_ftos_32_32, + Op_ftou_32_32, + Op_ftos_32_64, + Op_ftou_32_64, + Op_sext_64_32, + Op_ftos_64_32, + Op_ftou_64_32, + Op_ftos_64_64, + Op_ftou_64_64, + Op_stof_32_32, + Op_utof_32_32, + Op_stof_32_64, + Op_utof_32_64, + Op_ftof_32_64, + Op_stof_64_32, + Op_utof_64_32, + Op_stof_64_64, + Op_utof_64_64, + Op_ftof_64_32, + Op_sext8_32, + Op_sext16_32, + Op_sext8_64, + Op_sext16_64, + Op_sext32_64, + Op_memcpy, + Op_memset, + + Op_wrap_32_64 = Op_drop_32, + Op_zext_64_32 = Op_const_0_32, + Op_last = Op_memset, }; enum WasmOp { @@ -638,13 +780,11 @@ struct TypeInfo { }; struct Function { + uint32_t id; // Index to start of code in opcodes/operands. struct ProgramCounter entry_pc; uint32_t type_idx; - uint32_t locals_count; - // multi-word bitset with vm->types[type_idx].param_count + locals_count bits - // indexed from lsb of the first element, 0 -> 32-bit, 1 -> 64-bit - uint32_t *local_types; + uint32_t locals_size; }; enum ImpMod { @@ -688,7 +828,7 @@ struct Import { }; struct VirtualMachine { - uint64_t *stack; + uint32_t *stack; /// Points to one after the last stack item. uint32_t stack_top; struct ProgramCounter pc; @@ -869,7 +1009,6 @@ static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm, write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim)); write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim)); #endif - return WASI_ESUCCESS; } @@ -890,7 +1029,7 @@ static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, /// extern fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, - uint32_t argv, uint32_t argv_buf) + uint32_t argv, uint32_t argv_buf) { uint32_t argv_buf_i = 0; uint32_t arg_i = 0; @@ -910,7 +1049,7 @@ static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, /// extern fn random_get(buf: [*]u8, buf_len: usize) errno_t; static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, - uint32_t buf, uint32_t buf_len) + uint32_t buf, uint32_t buf_len) { #ifdef __linux__ if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) { @@ -1181,7 +1320,7 @@ static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, ///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { - fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64" %" PRIx64 "\n", vm->memory + text, n, n); + fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64 " %" PRIx64 "\n", vm->memory + text, n, n); } /// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; @@ -1189,9 +1328,15 @@ void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr); } +enum StackType { + ST_32, + ST_64, +}; + struct Label { enum WasmOp opcode; - uint32_t stack_depth; + uint32_t stack_index; + uint32_t stack_offset; struct TypeInfo type_info; // this is a UINT32_MAX terminated linked list that is stored in the operands array uint32_t ref_list; @@ -1209,7 +1354,7 @@ static uint32_t Label_operandCount(const struct Label *label) { } } -static bool Label_operandType(const struct Label *label, uint32_t index) { +static enum StackType Label_operandType(const struct Label *label, uint32_t index) { if (label->opcode == WasmOp_loop) { return bs_isSet(&label->type_info.param_types, index); } else { @@ -1217,29 +1362,69 @@ static bool Label_operandType(const struct Label *label, uint32_t index) { } } -static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint32_t *code_i, - struct ProgramCounter *pc) +#define max_stack_depth (1 << 12) + +struct StackInfo { + uint32_t top_index; + uint32_t top_offset; + uint32_t types[max_stack_depth >> 5]; + uint32_t offsets[max_stack_depth]; +}; + +static enum StackType si_top(const struct StackInfo *si) { + return bs_isSet(si->types, si->top_index - 1); +} + +static enum StackType si_local(const struct StackInfo *si, uint32_t local_idx) { + return bs_isSet(si->types, local_idx); +} + +static void si_push(struct StackInfo *si, enum StackType entry_type) { + bs_setValue(si->types, si->top_index, entry_type); + si->offsets[si->top_index] = si->top_offset; + si->top_index += 1; + si->top_offset += 1 + entry_type; +} + +static void si_pop(struct StackInfo *si, enum StackType entry_type) { + assert(si_top(si) == entry_type); + si->top_index -= 1; + si->top_offset -= 1 + entry_type; + assert(si->top_offset == si->offsets[si->top_index]); +} + +static void vm_decodeCode(struct VirtualMachine *vm, struct TypeInfo *func_type_info, + uint32_t *code_i, struct ProgramCounter *pc, struct StackInfo *stack) { const char *mod_ptr = vm->mod_ptr; uint8_t *opcodes = vm->opcodes; uint32_t *operands = vm->operands; - struct TypeInfo *func_type_info = &vm->types[func->type_idx]; - uint32_t unreachable_depth = 0; - uint32_t stack_depth = func_type_info->param_count + func->locals_count + 2; - static uint32_t stack_types[1 << (12 - 3)]; + // push return address + uint32_t frame_size = stack->top_offset; + si_push(stack, ST_32); + si_push(stack, ST_32); + uint32_t unreachable_depth = 0; + uint32_t label_i = 0; static struct Label labels[1 << 9]; #ifndef NDEBUG memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version #endif - uint32_t label_i = 0; labels[label_i].opcode = WasmOp_block; - labels[label_i].stack_depth = stack_depth; - labels[label_i].type_info = vm->types[func->type_idx]; + labels[label_i].stack_index = stack->top_index; + labels[label_i].stack_offset = stack->top_offset; + labels[label_i].type_info = *func_type_info; labels[label_i].ref_list = UINT32_MAX; + enum { + State_default, + State_bool_not, + } state = State_default; + for (;;) { + assert(stack->top_index >= labels[0].stack_index); + assert(stack->top_offset >= labels[0].stack_offset); enum WasmOp opcode = (uint8_t)mod_ptr[*code_i]; *code_i += 1; enum WasmPrefixedOp prefixed_opcode; @@ -1248,8 +1433,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand); //struct ProgramCounter old_pc = *pc; - uint32_t initial_stack_depth = stack_depth; - if (unreachable_depth == 0) { + if (unreachable_depth == 0) switch (opcode) { case WasmOp_unreachable: case WasmOp_nop: @@ -1258,58 +1442,62 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_else: case WasmOp_end: case WasmOp_br: - case WasmOp_call: case WasmOp_return: - break; + case WasmOp_call: + case WasmOp_local_get: + case WasmOp_local_set: + case WasmOp_local_tee: + case WasmOp_global_get: + case WasmOp_global_set: + case WasmOp_drop: + case WasmOp_select: + break; // handled manually below case WasmOp_if: case WasmOp_br_if: case WasmOp_br_table: case WasmOp_call_indirect: - case WasmOp_drop: - case WasmOp_local_set: - case WasmOp_global_set: - stack_depth -= 1; + si_pop(stack, ST_32); break; - case WasmOp_select: - stack_depth -= 2; - break; - - case WasmOp_local_get: - case WasmOp_global_get: case WasmOp_memory_size: case WasmOp_i32_const: - case WasmOp_i64_const: case WasmOp_f32_const: + si_push(stack, ST_32); + break; + + case WasmOp_i64_const: case WasmOp_f64_const: - stack_depth += 1; + si_push(stack, ST_64); break; - case WasmOp_local_tee: case WasmOp_i32_load: - case WasmOp_i64_load: case WasmOp_f32_load: - case WasmOp_f64_load: case WasmOp_i32_load8_s: case WasmOp_i32_load8_u: case WasmOp_i32_load16_s: case WasmOp_i32_load16_u: + si_pop(stack, ST_32); + si_push(stack, ST_32); + break; + + case WasmOp_i64_load: + case WasmOp_f64_load: case WasmOp_i64_load8_s: case WasmOp_i64_load8_u: case WasmOp_i64_load16_s: case WasmOp_i64_load16_u: case WasmOp_i64_load32_s: case WasmOp_i64_load32_u: + si_pop(stack, ST_32); + si_push(stack, ST_64); + break; + case WasmOp_memory_grow: case WasmOp_i32_eqz: case WasmOp_i32_clz: case WasmOp_i32_ctz: case WasmOp_i32_popcnt: - case WasmOp_i64_eqz: - case WasmOp_i64_clz: - case WasmOp_i64_ctz: - case WasmOp_i64_popcnt: case WasmOp_f32_abs: case WasmOp_f32_neg: case WasmOp_f32_ceil: @@ -1317,6 +1505,32 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_f32_trunc: case WasmOp_f32_nearest: case WasmOp_f32_sqrt: + case WasmOp_i32_trunc_f32_s: + case WasmOp_i32_trunc_f32_u: + case WasmOp_f32_convert_i32_s: + case WasmOp_f32_convert_i32_u: + case WasmOp_i32_reinterpret_f32: + case WasmOp_f32_reinterpret_i32: + case WasmOp_i32_extend8_s: + case WasmOp_i32_extend16_s: + si_pop(stack, ST_32); + si_push(stack, ST_32); + break; + + case WasmOp_i64_eqz: + case WasmOp_i32_wrap_i64: + case WasmOp_i32_trunc_f64_s: + case WasmOp_i32_trunc_f64_u: + case WasmOp_f32_convert_i64_s: + case WasmOp_f32_convert_i64_u: + case WasmOp_f32_demote_f64: + si_pop(stack, ST_64); + si_push(stack, ST_32); + break; + + case WasmOp_i64_clz: + case WasmOp_i64_ctz: + case WasmOp_i64_popcnt: case WasmOp_f64_abs: case WasmOp_f64_neg: case WasmOp_f64_ceil: @@ -1324,48 +1538,45 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_f64_trunc: case WasmOp_f64_nearest: case WasmOp_f64_sqrt: - case WasmOp_i32_wrap_i64: - case WasmOp_i32_trunc_f32_s: - case WasmOp_i32_trunc_f32_u: - case WasmOp_i32_trunc_f64_s: - case WasmOp_i32_trunc_f64_u: - case WasmOp_i64_extend_i32_s: - case WasmOp_i64_extend_i32_u: - case WasmOp_i64_trunc_f32_s: - case WasmOp_i64_trunc_f32_u: case WasmOp_i64_trunc_f64_s: case WasmOp_i64_trunc_f64_u: - case WasmOp_f32_convert_i32_s: - case WasmOp_f32_convert_i32_u: - case WasmOp_f32_convert_i64_s: - case WasmOp_f32_convert_i64_u: - case WasmOp_f32_demote_f64: - case WasmOp_f64_convert_i32_s: - case WasmOp_f64_convert_i32_u: case WasmOp_f64_convert_i64_s: case WasmOp_f64_convert_i64_u: - case WasmOp_f64_promote_f32: - case WasmOp_i32_reinterpret_f32: case WasmOp_i64_reinterpret_f64: - case WasmOp_f32_reinterpret_i32: case WasmOp_f64_reinterpret_i64: - case WasmOp_i32_extend8_s: - case WasmOp_i32_extend16_s: case WasmOp_i64_extend8_s: case WasmOp_i64_extend16_s: case WasmOp_i64_extend32_s: + si_pop(stack, ST_64); + si_push(stack, ST_64); + break; + + case WasmOp_i64_extend_i32_s: + case WasmOp_i64_extend_i32_u: + case WasmOp_i64_trunc_f32_s: + case WasmOp_i64_trunc_f32_u: + case WasmOp_f64_convert_i32_s: + case WasmOp_f64_convert_i32_u: + case WasmOp_f64_promote_f32: + si_pop(stack, ST_32); + si_push(stack, ST_64); break; case WasmOp_i32_store: - case WasmOp_i64_store: case WasmOp_f32_store: - case WasmOp_f64_store: case WasmOp_i32_store8: case WasmOp_i32_store16: + si_pop(stack, ST_32); + si_pop(stack, ST_32); + break; + + case WasmOp_i64_store: + case WasmOp_f64_store: case WasmOp_i64_store8: case WasmOp_i64_store16: case WasmOp_i64_store32: - stack_depth -= 2; + si_pop(stack, ST_64); + si_pop(stack, ST_32); break; case WasmOp_i32_eq: @@ -1378,6 +1589,17 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_i32_le_u: case WasmOp_i32_ge_s: case WasmOp_i32_ge_u: + case WasmOp_f32_eq: + case WasmOp_f32_ne: + case WasmOp_f32_lt: + case WasmOp_f32_gt: + case WasmOp_f32_le: + case WasmOp_f32_ge: + si_pop(stack, ST_32); + si_pop(stack, ST_32); + si_push(stack, ST_32); + break; + case WasmOp_i64_eq: case WasmOp_i64_ne: case WasmOp_i64_lt_s: @@ -1388,18 +1610,17 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_i64_le_u: case WasmOp_i64_ge_s: case WasmOp_i64_ge_u: - case WasmOp_f32_eq: - case WasmOp_f32_ne: - case WasmOp_f32_lt: - case WasmOp_f32_gt: - case WasmOp_f32_le: - case WasmOp_f32_ge: case WasmOp_f64_eq: case WasmOp_f64_ne: case WasmOp_f64_lt: case WasmOp_f64_gt: case WasmOp_f64_le: case WasmOp_f64_ge: + si_pop(stack, ST_64); + si_pop(stack, ST_64); + si_push(stack, ST_32); + break; + case WasmOp_i32_add: case WasmOp_i32_sub: case WasmOp_i32_mul: @@ -1415,6 +1636,18 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_i32_shr_u: case WasmOp_i32_rotl: case WasmOp_i32_rotr: + case WasmOp_f32_add: + case WasmOp_f32_sub: + case WasmOp_f32_mul: + case WasmOp_f32_div: + case WasmOp_f32_min: + case WasmOp_f32_max: + case WasmOp_f32_copysign: + si_pop(stack, ST_32); + si_pop(stack, ST_32); + si_push(stack, ST_32); + break; + case WasmOp_i64_add: case WasmOp_i64_sub: case WasmOp_i64_mul: @@ -1430,13 +1663,6 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_i64_shr_u: case WasmOp_i64_rotl: case WasmOp_i64_rotr: - case WasmOp_f32_add: - case WasmOp_f32_sub: - case WasmOp_f32_mul: - case WasmOp_f32_div: - case WasmOp_f32_min: - case WasmOp_f32_max: - case WasmOp_f32_copysign: case WasmOp_f64_add: case WasmOp_f64_sub: case WasmOp_f64_mul: @@ -1444,19 +1670,35 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_f64_min: case WasmOp_f64_max: case WasmOp_f64_copysign: - stack_depth -= 1; + si_pop(stack, ST_64); + si_pop(stack, ST_64); + si_push(stack, ST_64); break; case WasmOp_prefixed: switch (prefixed_opcode) { case WasmPrefixedOp_i32_trunc_sat_f32_s: case WasmPrefixedOp_i32_trunc_sat_f32_u: + si_pop(stack, ST_32); + si_push(stack, ST_32); + break; + case WasmPrefixedOp_i32_trunc_sat_f64_s: case WasmPrefixedOp_i32_trunc_sat_f64_u: + si_pop(stack, ST_64); + si_push(stack, ST_32); + break; + case WasmPrefixedOp_i64_trunc_sat_f32_s: case WasmPrefixedOp_i64_trunc_sat_f32_u: + si_pop(stack, ST_32); + si_push(stack, ST_64); + break; + case WasmPrefixedOp_i64_trunc_sat_f64_s: case WasmPrefixedOp_i64_trunc_sat_f64_u: + si_pop(stack, ST_64); + si_push(stack, ST_64); break; case WasmPrefixedOp_memory_init: @@ -1464,8 +1706,15 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmPrefixedOp_memory_fill: case WasmPrefixedOp_table_init: case WasmPrefixedOp_table_copy: + si_pop(stack, ST_32); + si_pop(stack, ST_32); + si_pop(stack, ST_32); + break; + case WasmPrefixedOp_table_fill: - stack_depth -= 3; + si_pop(stack, ST_32); + panic("si_pop(stack, unreachable);"); + si_pop(stack, ST_32); break; case WasmPrefixedOp_data_drop: @@ -1473,11 +1722,13 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case WasmPrefixedOp_table_grow: - stack_depth -= 1; + si_pop(stack, ST_32); + panic("si_pop(stack, unreachable);"); + si_push(stack, ST_32); break; case WasmPrefixedOp_table_size: - stack_depth += 1; + si_push(stack, ST_32); break; default: panic("unexpected prefixed opcode"); @@ -1486,235 +1737,14 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint default: panic("unexpected opcode"); } - switch (opcode) { - case WasmOp_unreachable: - case WasmOp_nop: - case WasmOp_block: - case WasmOp_loop: - case WasmOp_else: - case WasmOp_end: - case WasmOp_br: - case WasmOp_call: - case WasmOp_return: - case WasmOp_if: - case WasmOp_br_if: - case WasmOp_br_table: - case WasmOp_call_indirect: - case WasmOp_drop: - case WasmOp_select: - case WasmOp_local_set: - case WasmOp_local_get: - case WasmOp_local_tee: - case WasmOp_global_set: - case WasmOp_global_get: - case WasmOp_i32_store: - case WasmOp_i64_store: - case WasmOp_f32_store: - case WasmOp_f64_store: - case WasmOp_i32_store8: - case WasmOp_i32_store16: - case WasmOp_i64_store8: - case WasmOp_i64_store16: - case WasmOp_i64_store32: - break; - - case WasmOp_i32_const: - case WasmOp_f32_const: - case WasmOp_memory_size: - case WasmOp_i32_load: - case WasmOp_f32_load: - case WasmOp_i32_load8_s: - case WasmOp_i32_load8_u: - case WasmOp_i32_load16_s: - case WasmOp_i32_load16_u: - case WasmOp_memory_grow: - case WasmOp_i32_eqz: - case WasmOp_i32_clz: - case WasmOp_i32_ctz: - case WasmOp_i32_popcnt: - case WasmOp_i64_eqz: - case WasmOp_f32_abs: - case WasmOp_f32_neg: - case WasmOp_f32_ceil: - case WasmOp_f32_floor: - case WasmOp_f32_trunc: - case WasmOp_f32_nearest: - case WasmOp_f32_sqrt: - case WasmOp_i32_wrap_i64: - case WasmOp_i32_trunc_f32_s: - case WasmOp_i32_trunc_f32_u: - case WasmOp_i32_trunc_f64_s: - case WasmOp_i32_trunc_f64_u: - case WasmOp_f32_convert_i32_s: - case WasmOp_f32_convert_i32_u: - case WasmOp_f32_convert_i64_s: - case WasmOp_f32_convert_i64_u: - case WasmOp_f32_demote_f64: - case WasmOp_i32_reinterpret_f32: - case WasmOp_f32_reinterpret_i32: - case WasmOp_i32_extend8_s: - case WasmOp_i32_extend16_s: - case WasmOp_i32_eq: - case WasmOp_i32_ne: - case WasmOp_i32_lt_s: - case WasmOp_i32_lt_u: - case WasmOp_i32_gt_s: - case WasmOp_i32_gt_u: - case WasmOp_i32_le_s: - case WasmOp_i32_le_u: - case WasmOp_i32_ge_s: - case WasmOp_i32_ge_u: - case WasmOp_i64_eq: - case WasmOp_i64_ne: - case WasmOp_i64_lt_s: - case WasmOp_i64_lt_u: - case WasmOp_i64_gt_s: - case WasmOp_i64_gt_u: - case WasmOp_i64_le_s: - case WasmOp_i64_le_u: - case WasmOp_i64_ge_s: - case WasmOp_i64_ge_u: - case WasmOp_f32_eq: - case WasmOp_f32_ne: - case WasmOp_f32_lt: - case WasmOp_f32_gt: - case WasmOp_f32_le: - case WasmOp_f32_ge: - case WasmOp_f64_eq: - case WasmOp_f64_ne: - case WasmOp_f64_lt: - case WasmOp_f64_gt: - case WasmOp_f64_le: - case WasmOp_f64_ge: - case WasmOp_i32_add: - case WasmOp_i32_sub: - case WasmOp_i32_mul: - case WasmOp_i32_div_s: - case WasmOp_i32_div_u: - case WasmOp_i32_rem_s: - case WasmOp_i32_rem_u: - case WasmOp_i32_and: - case WasmOp_i32_or: - case WasmOp_i32_xor: - case WasmOp_i32_shl: - case WasmOp_i32_shr_s: - case WasmOp_i32_shr_u: - case WasmOp_i32_rotl: - case WasmOp_i32_rotr: - case WasmOp_f32_add: - case WasmOp_f32_sub: - case WasmOp_f32_mul: - case WasmOp_f32_div: - case WasmOp_f32_min: - case WasmOp_f32_max: - case WasmOp_f32_copysign: - bs_unset(stack_types, stack_depth - 1); - break; - - case WasmOp_i64_const: - case WasmOp_f64_const: - case WasmOp_i64_load: - case WasmOp_f64_load: - case WasmOp_i64_load8_s: - case WasmOp_i64_load8_u: - case WasmOp_i64_load16_s: - case WasmOp_i64_load16_u: - case WasmOp_i64_load32_s: - case WasmOp_i64_load32_u: - case WasmOp_i64_clz: - case WasmOp_i64_ctz: - case WasmOp_i64_popcnt: - case WasmOp_f64_abs: - case WasmOp_f64_neg: - case WasmOp_f64_ceil: - case WasmOp_f64_floor: - case WasmOp_f64_trunc: - case WasmOp_f64_nearest: - case WasmOp_f64_sqrt: - case WasmOp_i64_extend_i32_s: - case WasmOp_i64_extend_i32_u: - case WasmOp_i64_trunc_f32_s: - case WasmOp_i64_trunc_f32_u: - case WasmOp_i64_trunc_f64_s: - case WasmOp_i64_trunc_f64_u: - case WasmOp_f64_convert_i32_s: - case WasmOp_f64_convert_i32_u: - case WasmOp_f64_convert_i64_s: - case WasmOp_f64_convert_i64_u: - case WasmOp_f64_promote_f32: - case WasmOp_i64_reinterpret_f64: - case WasmOp_f64_reinterpret_i64: - case WasmOp_i64_extend8_s: - case WasmOp_i64_extend16_s: - case WasmOp_i64_extend32_s: - case WasmOp_i64_add: - case WasmOp_i64_sub: - case WasmOp_i64_mul: - case WasmOp_i64_div_s: - case WasmOp_i64_div_u: - case WasmOp_i64_rem_s: - case WasmOp_i64_rem_u: - case WasmOp_i64_and: - case WasmOp_i64_or: - case WasmOp_i64_xor: - case WasmOp_i64_shl: - case WasmOp_i64_shr_s: - case WasmOp_i64_shr_u: - case WasmOp_i64_rotl: - case WasmOp_i64_rotr: - case WasmOp_f64_add: - case WasmOp_f64_sub: - case WasmOp_f64_mul: - case WasmOp_f64_div: - case WasmOp_f64_min: - case WasmOp_f64_max: - case WasmOp_f64_copysign: - bs_set(stack_types, stack_depth - 1); - break; - - case WasmOp_prefixed: - switch (prefixed_opcode) { - case WasmPrefixedOp_memory_init: - case WasmPrefixedOp_memory_copy: - case WasmPrefixedOp_memory_fill: - case WasmPrefixedOp_table_init: - case WasmPrefixedOp_table_copy: - case WasmPrefixedOp_table_fill: - case WasmPrefixedOp_data_drop: - case WasmPrefixedOp_elem_drop: - break; - - case WasmPrefixedOp_i32_trunc_sat_f32_s: - case WasmPrefixedOp_i32_trunc_sat_f32_u: - case WasmPrefixedOp_i32_trunc_sat_f64_s: - case WasmPrefixedOp_i32_trunc_sat_f64_u: - case WasmPrefixedOp_table_grow: - case WasmPrefixedOp_table_size: - bs_unset(stack_types, stack_depth - 1); - break; - - case WasmPrefixedOp_i64_trunc_sat_f32_s: - case WasmPrefixedOp_i64_trunc_sat_f32_u: - case WasmPrefixedOp_i64_trunc_sat_f64_s: - case WasmPrefixedOp_i64_trunc_sat_f64_u: - bs_set(stack_types, stack_depth - 1); - break; - - default: panic("unexpected prefixed opcode"); - } - break; - - default: panic("unexpected opcode"); - } - } - - switch (opcode) { - case WasmOp_unreachable: - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_unreachable; - pc->opcode += 1; - } - break; + switch (opcode) { + case WasmOp_unreachable: + if (unreachable_depth == 0) { + opcodes[pc->opcode] = Op_unreachable; + pc->opcode += 1; + unreachable_depth += 1; + } + break; case WasmOp_nop: case WasmOp_i32_reinterpret_f32: @@ -1748,11 +1778,19 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; default: panic("unexpected param type"); } - } else { - label->type_info = vm->types[block_type]; + } else label->type_info = vm->types[block_type]; + + uint32_t param_i = label->type_info.param_count; + while (param_i > 0) { + param_i -= 1; + si_pop(stack, bs_isSet(&label->type_info.param_types, param_i)); } - label->stack_depth = stack_depth - label->type_info.param_count; + label->stack_index = stack->top_index; + label->stack_offset = stack->top_offset; label->ref_list = UINT32_MAX; + for (; param_i < label->type_info.param_count; param_i += 1) + si_push(stack, bs_isSet(&label->type_info.param_types, param_i)); + switch (opcode) { case WasmOp_block: break; @@ -1762,7 +1800,10 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case WasmOp_if: - opcodes[pc->opcode] = Op_br_if_eqz_void; + if (state == State_bool_not) { + pc->opcode -= 1; + opcodes[pc->opcode] = Op_br_nez_void; + } else opcodes[pc->opcode] = Op_br_eqz_void; pc->opcode += 1; operands[pc->operand] = 0; label->extra.else_ref = pc->operand + 1; @@ -1771,7 +1812,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint default: panic("unexpected label opcode"); } - } + } else unreachable_depth += 1; } break; @@ -1780,8 +1821,16 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint struct Label *label = &labels[label_i]; assert(label->opcode == WasmOp_if); label->opcode = WasmOp_else; + if (unreachable_depth == 0) { uint32_t operand_count = Label_operandCount(label); + for (uint32_t operand_i = operand_count; operand_i > 0; ) { + operand_i -= 1; + si_pop(stack, Label_operandType(label, operand_i)); + } + assert(stack->top_index == label->stack_index); + assert(stack->top_offset == label->stack_offset); + switch (operand_count) { case 0: opcodes[pc->opcode] = Op_br_void; @@ -1790,31 +1839,30 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case 1: //fprintf(stderr, "label_i=%u operand_type=%d\n", // label_i, Label_operandType(label, 0)); - if (Label_operandType(label, 0)) { - opcodes[pc->opcode] = Op_br_64; - } else { - opcodes[pc->opcode] = Op_br_32; + switch (Label_operandType(label, 0)) { + case ST_32: opcodes[pc->opcode] = Op_br_32; break; + case ST_64: opcodes[pc->opcode] = Op_br_64; break; } break; default: panic("unexpected operand count"); } pc->opcode += 1; - operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 0] = stack->top_offset - label->stack_offset; operands[pc->operand + 1] = label->ref_list; label->ref_list = pc->operand + 1; pc->operand += 3; - assert(stack_depth - label->type_info.result_count == label->stack_depth); } else unreachable_depth = 0; + operands[label->extra.else_ref + 0] = pc->opcode; operands[label->extra.else_ref + 1] = pc->operand; - stack_depth = label->stack_depth + label->type_info.param_count; + for (uint32_t param_i = 0; param_i < label->type_info.param_count; param_i += 1) + si_push(stack, bs_isSet(&label->type_info.param_types, param_i)); } break; case WasmOp_end: if (unreachable_depth <= 1) { - unreachable_depth = 0; struct Label *label = &labels[label_i]; struct ProgramCounter *target_pc = (label->opcode == WasmOp_loop) ? &label->extra.loop_pc : pc; if (label->opcode == WasmOp_if) { @@ -1828,33 +1876,44 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint operands[ref + 1] = target_pc->operand; ref = next_ref; } - stack_depth = label->stack_depth + label->type_info.result_count; + + if (unreachable_depth == 0) { + for (uint32_t result_i = label->type_info.result_count; result_i > 0; ) { + result_i -= 1; + si_pop(stack, bs_isSet(&label->type_info.result_types, result_i)); + } + } else unreachable_depth = 0; if (label_i == 0) { - uint32_t operand_count = Label_operandCount(&labels[0]); - switch (operand_count) { + assert(stack->top_index == label->stack_index); + assert(stack->top_offset == label->stack_offset); + + switch (labels[0].type_info.result_count) { case 0: opcodes[pc->opcode] = Op_return_void; break; case 1: - switch ((int)Label_operandType(&labels[0], 0)) { - case false: opcodes[pc->opcode] = Op_return_32; break; - case true: opcodes[pc->opcode] = Op_return_64; break; + switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) { + case ST_32: opcodes[pc->opcode] = Op_return_32; break; + case ST_64: opcodes[pc->opcode] = Op_return_64; break; } break; default: panic("unexpected operand count"); } pc->opcode += 1; - operands[pc->operand + 0] = 2 + operand_count; - stack_depth -= operand_count; - assert(stack_depth == labels[0].stack_depth); - operands[pc->operand + 1] = stack_depth; + operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset; + operands[pc->operand + 1] = frame_size; pc->operand += 2; return; } label_i -= 1; + + stack->top_index = label->stack_index; + stack->top_offset = label->stack_offset; + for (uint32_t result_i = 0; result_i < label->type_info.result_count; result_i += 1) + si_push(stack, bs_isSet(&label->type_info.result_types, result_i)); } else unreachable_depth -= 1; break; @@ -1865,6 +1924,12 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint if (unreachable_depth == 0) { struct Label *label = &labels[label_i - label_idx]; uint32_t operand_count = Label_operandCount(label); + uint32_t operand_i = operand_count; + while (operand_i > 0) { + operand_i -= 1; + si_pop(stack, Label_operandType(label, operand_i)); + } + switch (opcode) { case WasmOp_br: switch (operand_count) { @@ -1873,9 +1938,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint break; case 1: - switch ((int)Label_operandType(label, 0)) { - case false: opcodes[pc->opcode] = Op_br_32; break; - case true: opcodes[pc->opcode] = Op_br_64; break; + switch (Label_operandType(label, 0)) { + case ST_32: opcodes[pc->opcode] = Op_br_32; break; + case ST_64: opcodes[pc->opcode] = Op_br_64; break; } break; @@ -1886,13 +1951,27 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint case WasmOp_br_if: switch (operand_count) { case 0: - opcodes[pc->opcode] = Op_br_if_nez_void; + if (state == State_bool_not) { + pc->opcode -= 1; + opcodes[pc->opcode] = Op_br_eqz_void; + } else opcodes[pc->opcode] = Op_br_nez_void; break; case 1: - switch ((int)Label_operandType(label, 0)) { - case false: opcodes[pc->opcode] = Op_br_if_nez_32; break; - case true: opcodes[pc->opcode] = Op_br_if_nez_64; break; + switch (Label_operandType(label, 0)) { + case ST_32: + if (state == State_bool_not) { + pc->opcode -= 1; + opcodes[pc->opcode] = Op_br_eqz_32; + } else opcodes[pc->opcode] = Op_br_nez_32; + break; + + case ST_64: + if (state == State_bool_not) { + pc->opcode -= 1; + opcodes[pc->opcode] = Op_br_eqz_64; + } else opcodes[pc->opcode] = Op_br_nez_64; + break; } break; @@ -1900,13 +1979,26 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint } break; - default: panic("unreachable"); + default: panic("unexpected opcode"); } pc->opcode += 1; - operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 0] = stack->top_offset - label->stack_offset; operands[pc->operand + 1] = label->ref_list; label->ref_list = pc->operand + 1; pc->operand += 3; + + switch (opcode) { + case WasmOp_br: + unreachable_depth += 1; + break; + + case WasmOp_br_if: + for (; operand_i < operand_count; operand_i += 1) + si_push(stack, Label_operandType(label, operand_i)); + break; + + default: panic("unexpected opcode"); + } } } break; @@ -1918,17 +2010,22 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint uint32_t label_idx = read32_uleb128(mod_ptr, code_i); if (unreachable_depth != 0) continue; struct Label *label = &labels[label_i - label_idx]; - uint32_t operand_count = Label_operandCount(label); if (i == 0) { + uint32_t operand_count = Label_operandCount(label); + for (uint32_t operand_i = operand_count; operand_i > 0; ) { + operand_i -= 1; + si_pop(stack, Label_operandType(label, operand_i)); + } + switch (operand_count) { case 0: opcodes[pc->opcode] = Op_br_table_void; break; case 1: - switch ((int)Label_operandType(label, 0)) { - case false: opcodes[pc->opcode] = Op_br_table_32; break; - case true: opcodes[pc->opcode] = Op_br_table_64; break; + switch (Label_operandType(label, 0)) { + case ST_32: opcodes[pc->opcode] = Op_br_table_32; break; + case ST_64: opcodes[pc->opcode] = Op_br_table_64; break; } break; @@ -1938,11 +2035,41 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint operands[pc->operand] = labels_len; pc->operand += 1; } - operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; + operands[pc->operand + 0] = stack->top_offset - label->stack_offset; operands[pc->operand + 1] = label->ref_list; label->ref_list = pc->operand + 1; pc->operand += 3; } + if (unreachable_depth == 0) unreachable_depth += 1; + } + break; + + case WasmOp_return: + if (unreachable_depth == 0) { + for (uint32_t result_i = labels[0].type_info.result_count; result_i > 0; ) { + result_i -= 1; + si_pop(stack, bs_isSet(&labels[0].type_info.result_types, result_i)); + } + + switch (labels[0].type_info.result_count) { + case 0: + opcodes[pc->opcode] = Op_return_void; + break; + + case 1: + switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) { + case ST_32: opcodes[pc->opcode] = Op_return_32; break; + case ST_64: opcodes[pc->opcode] = Op_return_64; break; + } + break; + + default: panic("unexpected operand count"); + } + pc->opcode += 1; + operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset; + operands[pc->operand + 1] = frame_size; + pc->operand += 2; + unreachable_depth += 1; } break; @@ -1950,19 +2077,28 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint { uint32_t fn_id = read32_uleb128(mod_ptr, code_i); if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_call; - pc->opcode += 1; - operands[pc->operand] = fn_id; - pc->operand += 1; - uint32_t type_idx = (fn_id < vm->imports_len) ? - vm->imports[fn_id].type_idx : - vm->functions[fn_id - vm->imports_len].type_idx; + uint32_t type_idx; + if (fn_id < vm->imports_len) { + opcodes[pc->opcode + 0] = Op_call_import; + opcodes[pc->opcode + 1] = fn_id; + pc->opcode += 2; + type_idx = vm->imports[fn_id].type_idx; + } else { + uint32_t fn_idx = fn_id - vm->imports_len; + opcodes[pc->opcode] = Op_call_func; + pc->opcode += 1; + operands[pc->operand] = fn_idx; + pc->operand += 1; + type_idx = vm->functions[fn_idx].type_idx; + } struct TypeInfo *type_info = &vm->types[type_idx]; - stack_depth -= type_info->param_count; + + for (uint32_t param_i = type_info->param_count; param_i > 0; ) { + param_i -= 1; + si_pop(stack, bs_isSet(&type_info->param_types, param_i)); + } for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) - bs_setValue(stack_types, stack_depth + result_i, - bs_isSet(&type_info->result_types, result_i)); - stack_depth += type_info->result_count; + si_push(stack, bs_isSet(&type_info->result_types, result_i)); } } break; @@ -1972,171 +2108,144 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint uint32_t type_idx = read32_uleb128(mod_ptr, code_i); if (read32_uleb128(mod_ptr, code_i) != 0) panic("unexpected table index"); if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm; - opcodes[pc->opcode + 1] = opcode; - pc->opcode += 2; + opcodes[pc->opcode] = Op_call_indirect; + pc->opcode += 1; + struct TypeInfo *type_info = &vm->types[type_idx]; - stack_depth -= type_info->param_count; + for (uint32_t param_i = type_info->param_count; param_i > 0; ) { + param_i -= 1; + si_pop(stack, bs_isSet(&type_info->param_types, param_i)); + } for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) - bs_setValue(stack_types, stack_depth + result_i, - bs_isSet(&type_info->result_types, result_i)); - stack_depth += type_info->result_count; + si_push(stack, bs_isSet(&type_info->result_types, result_i)); } } break; - case WasmOp_return: - if (unreachable_depth <= 1) { - uint32_t operand_count = Label_operandCount(&labels[0]); - switch (operand_count) { - case 0: - opcodes[pc->opcode] = Op_return_void; + case WasmOp_select: + case WasmOp_drop: + if (unreachable_depth == 0) { + if (opcode == WasmOp_select) si_pop(stack, ST_32); + enum StackType operand_type = si_top(stack); + si_pop(stack, operand_type); + if (opcode == WasmOp_select) { + si_pop(stack, operand_type); + si_push(stack, operand_type); + } + switch (opcode) { + case WasmOp_select: + switch (operand_type) { + case ST_32: opcodes[pc->opcode] = Op_select_32; break; + case ST_64: opcodes[pc->opcode] = Op_select_64; break; + } break; - case 1: - switch ((int)Label_operandType(&labels[0], 0)) { - case false: opcodes[pc->opcode] = Op_return_32; break; - case true: opcodes[pc->opcode] = Op_return_64; break; + case WasmOp_drop: + switch (operand_type) { + case ST_32: opcodes[pc->opcode] = Op_drop_32; break; + case ST_64: opcodes[pc->opcode] = Op_drop_64; break; } break; - default: panic("unexpected operand count"); + default: panic("unexpected opcode"); } pc->opcode += 1; - operands[pc->operand + 0] = 2 + stack_depth - labels[0].stack_depth; - stack_depth -= operand_count; - operands[pc->operand + 1] = stack_depth; - pc->operand += 2; } break; - case WasmOp_select: - case WasmOp_drop: - if (unreachable_depth == 0) { - switch ((int)bs_isSet(stack_types, stack_depth)) { - case false: + case WasmOp_local_get: + case WasmOp_local_set: + case WasmOp_local_tee: + { + uint32_t local_idx = read32_uleb128(mod_ptr, code_i); + if (unreachable_depth == 0) { + enum StackType local_type = si_local(stack, local_idx); switch (opcode) { - case WasmOp_select: - opcodes[pc->opcode] = Op_select_32; + case WasmOp_local_get: + switch (local_type) { + case ST_32: opcodes[pc->opcode] = Op_local_get_32; break; + case ST_64: opcodes[pc->opcode] = Op_local_get_64; break; + } break; - case WasmOp_drop: - opcodes[pc->opcode] = Op_drop_32; + case WasmOp_local_set: + switch (local_type) { + case ST_32: opcodes[pc->opcode] = Op_local_set_32; break; + case ST_64: opcodes[pc->opcode] = Op_local_set_64; break; + } + break; + + case WasmOp_local_tee: + switch (local_type) { + case ST_32: opcodes[pc->opcode] = Op_local_tee_32; break; + case ST_64: opcodes[pc->opcode] = Op_local_tee_64; break; + } break; default: panic("unexpected opcode"); } - break; - - case true: + pc->opcode += 1; + operands[pc->operand] = stack->top_offset - stack->offsets[local_idx]; + pc->operand += 1; switch (opcode) { - case WasmOp_select: - opcodes[pc->opcode] = Op_select_64; + case WasmOp_local_get: + si_push(stack, local_type); + break; + + case WasmOp_local_set: + si_pop(stack, local_type); break; - case WasmOp_drop: - opcodes[pc->opcode] = Op_drop_64; + case WasmOp_local_tee: + si_pop(stack, local_type); + si_push(stack, local_type); break; default: panic("unexpected opcode"); } - break; } - pc->opcode += 1; } break; - case WasmOp_local_get: - case WasmOp_local_set: - case WasmOp_local_tee: + case WasmOp_global_get: + case WasmOp_global_set: { - uint32_t local_idx = read32_uleb128(mod_ptr, code_i); + uint32_t global_idx = read32_uleb128(mod_ptr, code_i); if (unreachable_depth == 0) { - bool local_type = bs_isSet(func->local_types, local_idx); - switch ((int)local_type) { - case false: - switch (opcode) { - case WasmOp_local_get: - opcodes[pc->opcode] = Op_local_get_32; - break; - - case WasmOp_local_set: - opcodes[pc->opcode] = Op_local_set_32; - break; - - case WasmOp_local_tee: - opcodes[pc->opcode] = Op_local_tee_32; - break; - - default: panic("unexpected opcode"); + enum StackType global_type = ST_32; // all globals assumed to be 32-bit + switch (opcode) { + case WasmOp_global_get: + switch (global_idx) { + case 0: opcodes[pc->opcode] = Op_global_get_0_32; break; + default: opcodes[pc->opcode] = Op_global_get_32; break; } break; - case true: - switch (opcode) { - case WasmOp_local_get: - opcodes[pc->opcode] = Op_local_get_64; - break; + case WasmOp_global_set: + switch (global_idx) { + case 0: opcodes[pc->opcode] = Op_global_set_0_32; break; + default: opcodes[pc->opcode] = Op_global_set_32; break; + } + break; - case WasmOp_local_set: - opcodes[pc->opcode] = Op_local_set_64; - break; - - case WasmOp_local_tee: - opcodes[pc->opcode] = Op_local_tee_64; - break; - - default: panic("unexpected opcode"); - } - break; - } - pc->opcode += 1; - operands[pc->operand] = initial_stack_depth - local_idx; - pc->operand += 1; - if (opcode == WasmOp_local_get) bs_setValue(stack_types, stack_depth - 1, local_type); - } - } - break; - - case WasmOp_global_get: - case WasmOp_global_set: - { - uint32_t global_idx = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - switch (global_idx) { - case 0: - switch (opcode) { - case WasmOp_global_get: - opcodes[pc->opcode] = Op_global_get_0_32; - break; - - case WasmOp_global_set: - opcodes[pc->opcode] = Op_global_set_0_32; - break; - - default: panic("unexpected opcode"); - } - break; - - default: - switch (opcode) { - case WasmOp_global_get: - opcodes[pc->opcode] = Op_global_get_32; - break; - - case WasmOp_global_set: - opcodes[pc->opcode] = Op_global_set_32; - break; - - default: panic("unexpected opcode"); - } - break; + default: panic("unexpected opcode"); } pc->opcode += 1; if (global_idx != 0) { operands[pc->operand] = global_idx; pc->operand += 1; } + switch (opcode) { + case WasmOp_global_get: + si_push(stack, global_type); + break; + + case WasmOp_global_set: + si_pop(stack, global_type); + break; + + default: panic("unexpected opcode"); + } } } break; @@ -2169,11 +2278,111 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint uint32_t offset = read32_uleb128(mod_ptr, code_i); (void)alignment; if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm; - opcodes[pc->opcode + 1] = opcode; - pc->opcode += 2; - operands[pc->operand] = offset; - pc->operand += 1; + switch (opcode) { + default: break; + + case WasmOp_i64_store8: case WasmOp_i64_store16: case WasmOp_i64_store32: + opcodes[pc->opcode] = Op_drop_32; + pc->opcode += 1; + break; + } + switch (opcode) { + case WasmOp_i32_load8_s: case WasmOp_i32_load8_u: + case WasmOp_i64_load8_s: case WasmOp_i64_load8_u: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_load_0_8; break; + default: opcodes[pc->opcode] = Op_load_8; break; + } + break; + + case WasmOp_i32_load16_s: case WasmOp_i32_load16_u: + case WasmOp_i64_load16_s: case WasmOp_i64_load16_u: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_load_0_16; break; + default: opcodes[pc->opcode] = Op_load_16; break; + } + break; + + case WasmOp_i32_load: case WasmOp_f32_load: + case WasmOp_i64_load32_s: case WasmOp_i64_load32_u: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_load_0_32; break; + default: opcodes[pc->opcode] = Op_load_32; break; + } + break; + + case WasmOp_i64_load: case WasmOp_f64_load: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_load_0_64; break; + default: opcodes[pc->opcode] = Op_load_64; break; + } + break; + + case WasmOp_i32_store8: case WasmOp_i64_store8: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_store_0_8; break; + default: opcodes[pc->opcode] = Op_store_8; break; + } + break; + + case WasmOp_i32_store16: case WasmOp_i64_store16: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_store_0_16; break; + default: opcodes[pc->opcode] = Op_store_16; break; + } + break; + + case WasmOp_i32_store: case WasmOp_f32_store: case WasmOp_i64_store32: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_store_0_32; break; + default: opcodes[pc->opcode] = Op_store_32; break; + } + break; + + case WasmOp_i64_store: case WasmOp_f64_store: + switch (offset) { + case 0: opcodes[pc->opcode] = Op_store_0_64; break; + default: opcodes[pc->opcode] = Op_store_64; break; + } + break; + + default: panic("unexpected opcode"); + } + pc->opcode += 1; + switch (offset) { + case 0: break; + + default: + operands[pc->operand] = offset; + pc->operand += 1; + break; + } + switch (opcode) { + default: break; + + case WasmOp_i32_load8_s: case WasmOp_i64_load8_s: + opcodes[pc->opcode] = Op_sext8_32; + pc->opcode += 1; + break; + + case WasmOp_i32_load16_s: case WasmOp_i64_load16_s: + opcodes[pc->opcode] = Op_sext16_32; + pc->opcode += 1; + break; + } + switch (opcode) { + default: break; + + case WasmOp_i64_load8_s: case WasmOp_i64_load16_s: case WasmOp_i64_load32_s: + opcodes[pc->opcode] = Op_sext_64_32; + pc->opcode += 1; + break; + + case WasmOp_i64_load8_u: case WasmOp_i64_load16_u: case WasmOp_i64_load32_u: + opcodes[pc->opcode] = Op_zext_64_32; + pc->opcode += 1; + break; + } } } break; @@ -2184,110 +2393,224 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); *code_i += 1; if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm; - opcodes[pc->opcode + 1] = opcode; - pc->opcode += 2; + switch (opcode) { + case WasmOp_memory_size: opcodes[pc->opcode] = Op_mem_size; break; + case WasmOp_memory_grow: opcodes[pc->opcode] = Op_mem_grow; break; + default: panic("unexpected opcode"); + } + pc->opcode += 1; } } break; case WasmOp_i32_const: + case WasmOp_f32_const: { - uint32_t x = read32_ileb128(mod_ptr, code_i); + uint32_t value; + switch (opcode) { + case WasmOp_i32_const: value = read32_ileb128(mod_ptr, code_i); break; + + case WasmOp_f32_const: + value = read_u32_le(&mod_ptr[*code_i]); + *code_i += sizeof(value); + break; + + default: panic("unexpected opcode"); + } if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_const_32; + switch (value) { + case 0: opcodes[pc->opcode] = Op_const_0_32; break; + case 1: opcodes[pc->opcode] = Op_const_1_32; break; + + default: + opcodes[pc->opcode] = Op_const_32; + operands[pc->operand] = value; + pc->operand += 1; + break; + + case UINT32_MAX: opcodes[pc->opcode] = Op_const_umax_32; break; + } pc->opcode += 1; - operands[pc->operand] = x; - pc->operand += 1; } } break; case WasmOp_i64_const: + case WasmOp_f64_const: { - uint64_t x = read64_ileb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_const_64; - pc->opcode += 1; - operands[pc->operand + 0] = x & UINT32_MAX; - operands[pc->operand + 1] = (x >> 32) & UINT32_MAX; - pc->operand += 2; - } - } - break; + uint64_t value; + switch (opcode) { + case WasmOp_i64_const: value = read64_ileb128(mod_ptr, code_i); break; - case WasmOp_f32_const: - { - uint32_t x; - memcpy(&x, mod_ptr + *code_i, 4); - *code_i += 4; - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_const_32; - pc->opcode += 1; - operands[pc->operand] = x; - pc->operand += 1; + case WasmOp_f64_const: + value = read_u64_le(&mod_ptr[*code_i]); + *code_i += sizeof(value); + break; + + default: panic("unexpected opcode"); } - } - break; - case WasmOp_f64_const: - { - uint64_t x; - memcpy(&x, mod_ptr + *code_i, 8); - *code_i += 8; if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_const_64; + switch (value) { + case 0: opcodes[pc->opcode] = Op_const_0_64; break; + case 1: opcodes[pc->opcode] = Op_const_1_64; break; + + default: + opcodes[pc->opcode] = Op_const_64; + operands[pc->operand + 0] = (uint32_t)(value >> 0); + operands[pc->operand + 1] = (uint32_t)(value >> 32); + pc->operand += 2; + break; + + case UINT64_MAX: opcodes[pc->opcode] = Op_const_umax_64; break; + } pc->opcode += 1; - operands[pc->operand + 0] = x & UINT32_MAX; - operands[pc->operand + 1] = (x >> 32) & UINT32_MAX; - pc->operand += 2; } } break; - case WasmOp_i32_add: - opcodes[pc->opcode] = Op_add_32; - pc->opcode += 1; - break; - - case WasmOp_i32_and: - opcodes[pc->opcode] = Op_and_32; - pc->opcode += 1; - break; - default: if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm; - opcodes[pc->opcode + 1] = opcode; - pc->opcode += 2; + switch (opcode) { + case WasmOp_i32_eqz: opcodes[pc->opcode] = Op_eqz_32; break; + case WasmOp_i32_eq: opcodes[pc->opcode] = Op_eq_32; break; + case WasmOp_i32_ne: opcodes[pc->opcode] = Op_ne_32; break; + case WasmOp_i32_lt_s: opcodes[pc->opcode] = Op_slt_32; break; + case WasmOp_i32_lt_u: opcodes[pc->opcode] = Op_ult_32; break; + case WasmOp_i32_gt_s: opcodes[pc->opcode] = Op_sgt_32; break; + case WasmOp_i32_gt_u: opcodes[pc->opcode] = Op_ugt_32; break; + case WasmOp_i32_le_s: opcodes[pc->opcode] = Op_sle_32; break; + case WasmOp_i32_le_u: opcodes[pc->opcode] = Op_ule_32; break; + case WasmOp_i32_ge_s: opcodes[pc->opcode] = Op_sge_32; break; + case WasmOp_i32_ge_u: opcodes[pc->opcode] = Op_uge_32; break; + case WasmOp_i64_eqz: opcodes[pc->opcode] = Op_eqz_64; break; + case WasmOp_i64_eq: opcodes[pc->opcode] = Op_eq_64; break; + case WasmOp_i64_ne: opcodes[pc->opcode] = Op_ne_64; break; + case WasmOp_i64_lt_s: opcodes[pc->opcode] = Op_slt_64; break; + case WasmOp_i64_lt_u: opcodes[pc->opcode] = Op_ult_64; break; + case WasmOp_i64_gt_s: opcodes[pc->opcode] = Op_sgt_64; break; + case WasmOp_i64_gt_u: opcodes[pc->opcode] = Op_ugt_64; break; + case WasmOp_i64_le_s: opcodes[pc->opcode] = Op_sle_64; break; + case WasmOp_i64_le_u: opcodes[pc->opcode] = Op_ule_64; break; + case WasmOp_i64_ge_s: opcodes[pc->opcode] = Op_sge_64; break; + case WasmOp_i64_ge_u: opcodes[pc->opcode] = Op_uge_64; break; + case WasmOp_f32_eq: opcodes[pc->opcode] = Op_feq_32; break; + case WasmOp_f32_ne: opcodes[pc->opcode] = Op_fne_32; break; + case WasmOp_f32_lt: opcodes[pc->opcode] = Op_flt_32; break; + case WasmOp_f32_gt: opcodes[pc->opcode] = Op_fgt_32; break; + case WasmOp_f32_le: opcodes[pc->opcode] = Op_fle_32; break; + case WasmOp_f32_ge: opcodes[pc->opcode] = Op_fge_32; break; + case WasmOp_f64_eq: opcodes[pc->opcode] = Op_feq_64; break; + case WasmOp_f64_ne: opcodes[pc->opcode] = Op_fne_64; break; + case WasmOp_f64_lt: opcodes[pc->opcode] = Op_flt_64; break; + case WasmOp_f64_gt: opcodes[pc->opcode] = Op_fgt_64; break; + case WasmOp_f64_le: opcodes[pc->opcode] = Op_fle_64; break; + case WasmOp_f64_ge: opcodes[pc->opcode] = Op_fge_64; break; + case WasmOp_i32_clz: opcodes[pc->opcode] = Op_clz_32; break; + case WasmOp_i32_ctz: opcodes[pc->opcode] = Op_ctz_32; break; + case WasmOp_i32_popcnt: opcodes[pc->opcode] = Op_popcnt_32; break; + case WasmOp_i32_add: opcodes[pc->opcode] = Op_add_32; break; + case WasmOp_i32_sub: opcodes[pc->opcode] = Op_sub_32; break; + case WasmOp_i32_mul: opcodes[pc->opcode] = Op_mul_32; break; + case WasmOp_i32_div_s: opcodes[pc->opcode] = Op_sdiv_32; break; + case WasmOp_i32_div_u: opcodes[pc->opcode] = Op_udiv_32; break; + case WasmOp_i32_rem_s: opcodes[pc->opcode] = Op_srem_32; break; + case WasmOp_i32_rem_u: opcodes[pc->opcode] = Op_urem_32; break; + case WasmOp_i32_and: opcodes[pc->opcode] = Op_and_32; break; + case WasmOp_i32_or: opcodes[pc->opcode] = Op_or_32; break; + case WasmOp_i32_xor: opcodes[pc->opcode] = Op_xor_32; break; + case WasmOp_i32_shl: opcodes[pc->opcode] = Op_shl_32; break; + case WasmOp_i32_shr_s: opcodes[pc->opcode] = Op_ashr_32; break; + case WasmOp_i32_shr_u: opcodes[pc->opcode] = Op_lshr_32; break; + case WasmOp_i32_rotl: opcodes[pc->opcode] = Op_rol_32; break; + case WasmOp_i32_rotr: opcodes[pc->opcode] = Op_ror_32; break; + case WasmOp_i64_clz: opcodes[pc->opcode] = Op_clz_64; break; + case WasmOp_i64_ctz: opcodes[pc->opcode] = Op_ctz_64; break; + case WasmOp_i64_popcnt: opcodes[pc->opcode] = Op_popcnt_64; break; + case WasmOp_i64_add: opcodes[pc->opcode] = Op_add_64; break; + case WasmOp_i64_sub: opcodes[pc->opcode] = Op_sub_64; break; + case WasmOp_i64_mul: opcodes[pc->opcode] = Op_mul_64; break; + case WasmOp_i64_div_s: opcodes[pc->opcode] = Op_sdiv_64; break; + case WasmOp_i64_div_u: opcodes[pc->opcode] = Op_udiv_64; break; + case WasmOp_i64_rem_s: opcodes[pc->opcode] = Op_srem_64; break; + case WasmOp_i64_rem_u: opcodes[pc->opcode] = Op_urem_64; break; + case WasmOp_i64_and: opcodes[pc->opcode] = Op_and_64; break; + case WasmOp_i64_or: opcodes[pc->opcode] = Op_or_64; break; + case WasmOp_i64_xor: opcodes[pc->opcode] = Op_xor_64; break; + case WasmOp_i64_shl: opcodes[pc->opcode] = Op_shl_64; break; + case WasmOp_i64_shr_s: opcodes[pc->opcode] = Op_ashr_64; break; + case WasmOp_i64_shr_u: opcodes[pc->opcode] = Op_lshr_64; break; + case WasmOp_i64_rotl: opcodes[pc->opcode] = Op_rol_64; break; + case WasmOp_i64_rotr: opcodes[pc->opcode] = Op_ror_64; break; + case WasmOp_f32_abs: opcodes[pc->opcode] = Op_fabs_32; break; + case WasmOp_f32_neg: opcodes[pc->opcode] = Op_fneg_32; break; + case WasmOp_f32_ceil: opcodes[pc->opcode] = Op_ceil_32; break; + case WasmOp_f32_floor: opcodes[pc->opcode] = Op_floor_32; break; + case WasmOp_f32_trunc: opcodes[pc->opcode] = Op_trunc_32; break; + case WasmOp_f32_nearest: opcodes[pc->opcode] = Op_nearest_32; break; + case WasmOp_f32_sqrt: opcodes[pc->opcode] = Op_sqrt_32; break; + case WasmOp_f32_add: opcodes[pc->opcode] = Op_fadd_32; break; + case WasmOp_f32_sub: opcodes[pc->opcode] = Op_fsub_32; break; + case WasmOp_f32_mul: opcodes[pc->opcode] = Op_fmul_32; break; + case WasmOp_f32_div: opcodes[pc->opcode] = Op_fdiv_32; break; + case WasmOp_f32_min: opcodes[pc->opcode] = Op_fmin_32; break; + case WasmOp_f32_max: opcodes[pc->opcode] = Op_fmax_32; break; + case WasmOp_f32_copysign: opcodes[pc->opcode] = Op_copysign_32; break; + case WasmOp_f64_abs: opcodes[pc->opcode] = Op_fabs_64; break; + case WasmOp_f64_neg: opcodes[pc->opcode] = Op_fneg_64; break; + case WasmOp_f64_ceil: opcodes[pc->opcode] = Op_ceil_64; break; + case WasmOp_f64_floor: opcodes[pc->opcode] = Op_floor_64; break; + case WasmOp_f64_trunc: opcodes[pc->opcode] = Op_trunc_64; break; + case WasmOp_f64_nearest: opcodes[pc->opcode] = Op_nearest_64; break; + case WasmOp_f64_sqrt: opcodes[pc->opcode] = Op_sqrt_64; break; + case WasmOp_f64_add: opcodes[pc->opcode] = Op_fadd_64; break; + case WasmOp_f64_sub: opcodes[pc->opcode] = Op_fsub_64; break; + case WasmOp_f64_mul: opcodes[pc->opcode] = Op_fmul_64; break; + case WasmOp_f64_div: opcodes[pc->opcode] = Op_fdiv_64; break; + case WasmOp_f64_min: opcodes[pc->opcode] = Op_fmin_64; break; + case WasmOp_f64_max: opcodes[pc->opcode] = Op_fmax_64; break; + case WasmOp_f64_copysign: opcodes[pc->opcode] = Op_copysign_64; break; + case WasmOp_i32_wrap_i64: opcodes[pc->opcode] = Op_wrap_32_64; break; + case WasmOp_i32_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_32_32; break; + case WasmOp_i32_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_32_32; break; + case WasmOp_i32_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_32_64; break; + case WasmOp_i32_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_32_64; break; + case WasmOp_i64_extend_i32_s: opcodes[pc->opcode] = Op_sext_64_32; break; + case WasmOp_i64_extend_i32_u: opcodes[pc->opcode] = Op_zext_64_32; break; + case WasmOp_i64_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_64_32; break; + case WasmOp_i64_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_64_32; break; + case WasmOp_i64_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_64_64; break; + case WasmOp_i64_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_64_64; break; + case WasmOp_f32_convert_i32_s: opcodes[pc->opcode] = Op_stof_32_32; break; + case WasmOp_f32_convert_i32_u: opcodes[pc->opcode] = Op_utof_32_32; break; + case WasmOp_f32_convert_i64_s: opcodes[pc->opcode] = Op_stof_32_64; break; + case WasmOp_f32_convert_i64_u: opcodes[pc->opcode] = Op_utof_32_64; break; + case WasmOp_f32_demote_f64: opcodes[pc->opcode] = Op_ftof_32_64; break; + case WasmOp_f64_convert_i32_s: opcodes[pc->opcode] = Op_stof_64_32; break; + case WasmOp_f64_convert_i32_u: opcodes[pc->opcode] = Op_utof_64_32; break; + case WasmOp_f64_convert_i64_s: opcodes[pc->opcode] = Op_stof_64_64; break; + case WasmOp_f64_convert_i64_u: opcodes[pc->opcode] = Op_utof_64_64; break; + case WasmOp_f64_promote_f32: opcodes[pc->opcode] = Op_ftof_64_32; break; + case WasmOp_i32_extend8_s: opcodes[pc->opcode] = Op_sext8_32; break; + case WasmOp_i32_extend16_s: opcodes[pc->opcode] = Op_sext16_32; break; + case WasmOp_i64_extend8_s: opcodes[pc->opcode] = Op_sext8_64; break; + case WasmOp_i64_extend16_s: opcodes[pc->opcode] = Op_sext16_64; break; + case WasmOp_i64_extend32_s: opcodes[pc->opcode] = Op_sext32_64; break; + default: panic("unexpected opcode"); + } + pc->opcode += 1; } break; case WasmOp_prefixed: switch (prefixed_opcode) { - case WasmPrefixedOp_i32_trunc_sat_f32_s: - case WasmPrefixedOp_i32_trunc_sat_f32_u: - case WasmPrefixedOp_i32_trunc_sat_f64_s: - case WasmPrefixedOp_i32_trunc_sat_f64_u: - case WasmPrefixedOp_i64_trunc_sat_f32_s: - case WasmPrefixedOp_i64_trunc_sat_f32_u: - case WasmPrefixedOp_i64_trunc_sat_f64_s: - case WasmPrefixedOp_i64_trunc_sat_f64_u: - if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm_prefixed; - opcodes[pc->opcode + 1] = prefixed_opcode; - pc->opcode += 2; - } - break; - case WasmPrefixedOp_memory_copy: if (mod_ptr[*code_i + 0] != 0 || mod_ptr[*code_i + 1] != 0) panic("unexpected memory index"); *code_i += 2; if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm_prefixed; - opcodes[pc->opcode + 1] = prefixed_opcode; - pc->opcode += 2; + opcodes[pc->opcode] = Op_memcpy; + pc->opcode += 1; } break; @@ -2295,27 +2618,18 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); *code_i += 1; if (unreachable_depth == 0) { - opcodes[pc->opcode + 0] = Op_wasm_prefixed; - opcodes[pc->opcode + 1] = prefixed_opcode; - pc->opcode += 2; + opcodes[pc->opcode] = Op_memset; + pc->opcode += 1; } break; - default: panic("unreachable"); + default: panic("unexpected opcode"); } break; } - switch (opcode) { - case WasmOp_unreachable: - case WasmOp_return: - case WasmOp_br: - case WasmOp_br_table: - if (unreachable_depth == 0) unreachable_depth = 1; - break; - - default: - break; + default: state = State_default; break; + case WasmOp_i32_eqz: state = State_bool_not; break; } //for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) { @@ -2328,70 +2642,71 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint } static void vm_push_u32(struct VirtualMachine *vm, uint32_t value) { - vm->stack[vm->stack_top] = value; + vm->stack[vm->stack_top + 0] = value; vm->stack_top += 1; } static void vm_push_i32(struct VirtualMachine *vm, int32_t value) { - return vm_push_u32(vm, value); + vm_push_u32(vm, (uint32_t)value); } static void vm_push_u64(struct VirtualMachine *vm, uint64_t value) { - vm->stack[vm->stack_top] = value; - vm->stack_top += 1; + vm->stack[vm->stack_top + 0] = (uint32_t)(value >> 0); + vm->stack[vm->stack_top + 1] = (uint32_t)(value >> 32); + vm->stack_top += 2; } static void vm_push_i64(struct VirtualMachine *vm, int64_t value) { - return vm_push_u64(vm, value); + vm_push_u64(vm, (uint64_t)value); } static void vm_push_f32(struct VirtualMachine *vm, float value) { uint32_t integer; - memcpy(&integer, &value, 4); - return vm_push_u32(vm, integer); + memcpy(&integer, &value, sizeof(integer)); + vm_push_u32(vm, integer); } static void vm_push_f64(struct VirtualMachine *vm, double value) { uint64_t integer; - memcpy(&integer, &value, 8); - return vm_push_u64(vm, integer); + memcpy(&integer, &value, sizeof(integer)); + vm_push_u64(vm, integer); } static uint32_t vm_pop_u32(struct VirtualMachine *vm) { vm->stack_top -= 1; - return vm->stack[vm->stack_top]; + return vm->stack[vm->stack_top + 0]; } static int32_t vm_pop_i32(struct VirtualMachine *vm) { - return vm_pop_u32(vm); + return (int32_t)vm_pop_u32(vm); } static uint64_t vm_pop_u64(struct VirtualMachine *vm) { - vm->stack_top -= 1; - return vm->stack[vm->stack_top]; + vm->stack_top -= 2; + return vm->stack[vm->stack_top + 0] | (uint64_t)vm->stack[vm->stack_top + 1] << 32; } static int64_t vm_pop_i64(struct VirtualMachine *vm) { - return vm_pop_u64(vm); + return (int64_t)vm_pop_u64(vm); } static float vm_pop_f32(struct VirtualMachine *vm) { uint32_t integer = vm_pop_u32(vm); float result; - memcpy(&result, &integer, 4); + memcpy(&result, &integer, sizeof(result)); return result; } static double vm_pop_f64(struct VirtualMachine *vm) { uint64_t integer = vm_pop_u64(vm); double result; - memcpy(&result, &integer, 8); + memcpy(&result, &integer, sizeof(result)); return result; } -static void vm_callImport(struct VirtualMachine *vm, struct Import import) { - switch (import.mod) { - case ImpMod_wasi_snapshot_preview1: switch (import.name) { +static void vm_callImport(struct VirtualMachine *vm, const struct Import *import) { + switch (import->mod) { + case ImpMod_wasi_snapshot_preview1: switch (import->name) { case ImpName_fd_prestat_get: { uint32_t buf = vm_pop_u32(vm); @@ -2613,21 +2928,14 @@ static void vm_callImport(struct VirtualMachine *vm, struct Import import) { } } -static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) { - if (fn_id < vm->imports_len) { - struct Import imp = vm->imports[fn_id]; - return vm_callImport(vm, imp); - } - uint32_t fn_idx = fn_id - vm->imports_len; - struct Function *func = &vm->functions[fn_idx]; - +static void vm_call(struct VirtualMachine *vm, const struct Function *func) { //struct TypeInfo *type_info = &vm->types[func->type_idx]; - //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_count: %u\n", - // fn_id, type_info->param_count, type_info->result_count, func->locals_count); + //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_size: %u\n", + // func->id, type_info->param_count, type_info->result_count, func->locals_size); // Push zeroed locals to stack - memset(vm->stack + vm->stack_top, 0, func->locals_count * sizeof(uint64_t)); - vm->stack_top += func->locals_count; + memset(&vm->stack[vm->stack_top], 0, func->locals_size * sizeof(uint32_t)); + vm->stack_top += func->locals_size; vm_push_u32(vm, vm->pc.opcode); vm_push_u32(vm, vm->pc.operand); @@ -2667,36 +2975,41 @@ static void vm_br_u64(struct VirtualMachine *vm) { } static void vm_return_void(struct VirtualMachine *vm) { - uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; - uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; - - vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; - vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; + uint32_t frame_size = vm->operands[vm->pc.operand + 1]; vm->stack_top -= stack_adjust; + vm->pc.operand = vm_pop_u32(vm); + vm->pc.opcode = vm_pop_u32(vm); + + vm->stack_top -= frame_size; } static void vm_return_u32(struct VirtualMachine *vm) { - uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; - uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; - - vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; - vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; + uint32_t frame_size = vm->operands[vm->pc.operand + 1]; uint32_t result = vm_pop_u32(vm); + vm->stack_top -= stack_adjust; + vm->pc.operand = vm_pop_u32(vm); + vm->pc.opcode = vm_pop_u32(vm); + + vm->stack_top -= frame_size; vm_push_u32(vm, result); } static void vm_return_u64(struct VirtualMachine *vm) { - uint32_t ret_pc_offset = vm->operands[vm->pc.operand + 0]; - uint32_t stack_adjust = vm->operands[vm->pc.operand + 1]; - - vm->pc.opcode = vm->stack[vm->stack_top - ret_pc_offset]; - vm->pc.operand = vm->stack[vm->stack_top - ret_pc_offset + 1]; + uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; + uint32_t frame_size = vm->operands[vm->pc.operand + 1]; uint64_t result = vm_pop_u64(vm); + vm->stack_top -= stack_adjust; + vm->pc.operand = vm_pop_u32(vm); + vm->pc.opcode = vm_pop_u32(vm); + + vm->stack_top -= frame_size; vm_push_u64(vm, result); } @@ -2704,77 +3017,68 @@ static void vm_run(struct VirtualMachine *vm) { uint8_t *opcodes = vm->opcodes; uint32_t *operands = vm->operands; struct ProgramCounter *pc = &vm->pc; + uint32_t global_0 = vm->globals[0]; for (;;) { enum Op op = opcodes[pc->opcode]; + //fprintf(stderr, "stack[%u:%u]=%x:%x pc=%x:%x op=%u\n", + // vm->stack_top - 2, vm->stack_top - 1, + // vm->stack[vm->stack_top - 2], vm->stack[vm->stack_top - 1], + // pc->opcode, pc->operand, op); pc->opcode += 1; - //if (vm->stack_top > 0) { - // fprintf(stderr, "stack[%u]=%lx pc=%u:%u, op=%u\n", - // vm->stack_top - 1, vm->stack[vm->stack_top - 1], pc->opcode, pc->operand, op); - //} switch (op) { case Op_unreachable: panic("unreachable reached"); - case Op_br_void: vm_br_void(vm); break; - case Op_br_32: vm_br_u32(vm); break; - case Op_br_64: vm_br_u64(vm); break; - - case Op_br_if_nez_void: + case Op_br_nez_void: if (vm_pop_u32(vm) != 0) { vm_br_void(vm); } else { pc->operand += 3; } break; - - case Op_br_if_nez_32: + case Op_br_nez_32: if (vm_pop_u32(vm) != 0) { vm_br_u32(vm); } else { pc->operand += 3; } break; - - case Op_br_if_nez_64: + case Op_br_nez_64: if (vm_pop_u32(vm) != 0) { vm_br_u64(vm); } else { pc->operand += 3; } break; - - case Op_br_if_eqz_void: + case Op_br_eqz_void: if (vm_pop_u32(vm) == 0) { vm_br_void(vm); } else { pc->operand += 3; } break; - - case Op_br_if_eqz_32: + case Op_br_eqz_32: if (vm_pop_u32(vm) == 0) { vm_br_u32(vm); } else { pc->operand += 3; } break; - - case Op_br_if_eqz_64: + case Op_br_eqz_64: if (vm_pop_u32(vm) == 0) { vm_br_u64(vm); } else { pc->operand += 3; } break; - case Op_br_table_void: { uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); @@ -2782,7 +3086,6 @@ static void vm_run(struct VirtualMachine *vm) { vm_br_void(vm); } break; - case Op_br_table_32: { uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); @@ -2790,7 +3093,6 @@ static void vm_run(struct VirtualMachine *vm) { vm_br_u32(vm); } break; - case Op_br_table_64: { uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); @@ -2798,32 +3100,45 @@ static void vm_run(struct VirtualMachine *vm) { vm_br_u64(vm); } break; - case Op_return_void: vm_return_void(vm); break; - case Op_return_32: vm_return_u32(vm); break; - case Op_return_64: vm_return_u64(vm); break; - - case Op_call: + case Op_call_import: + { + uint8_t import_idx = opcodes[pc->opcode]; + pc->opcode += 1; + vm_callImport(vm, &vm->imports[import_idx]); + } + break; + case Op_call_func: { - uint32_t fn_id = operands[pc->operand]; + uint32_t func_idx = operands[pc->operand]; pc->operand += 1; - vm_call(vm, fn_id); + vm_call(vm, &vm->functions[func_idx]); + } + break; + case Op_call_indirect: + { + uint32_t fn_id = vm->table[vm_pop_u32(vm)]; + if (fn_id < vm->imports_len) + vm_callImport(vm, &vm->imports[fn_id]); + else + vm_call(vm, &vm->functions[fn_id - vm->imports_len]); } break; case Op_drop_32: - case Op_drop_64: vm->stack_top -= 1; break; - + case Op_drop_64: + vm->stack_top -= 2; + break; case Op_select_32: { uint32_t c = vm_pop_u32(vm); @@ -2833,7 +3148,6 @@ static void vm_run(struct VirtualMachine *vm) { vm_push_u32(vm, result); } break; - case Op_select_64: { uint32_t c = vm_pop_u32(vm); @@ -2846,49 +3160,53 @@ static void vm_run(struct VirtualMachine *vm) { case Op_local_get_32: { - uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; pc->operand += 1; vm_push_u32(vm, *local); } break; - case Op_local_get_64: { - uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; pc->operand += 1; - vm_push_u64(vm, *local); + vm_push_u64(vm, local[0] | (uint64_t)local[1] << 32); } break; - case Op_local_set_32: { - uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; pc->operand += 1; *local = vm_pop_u32(vm); } break; - case Op_local_set_64: { - uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; pc->operand += 1; - *local = vm_pop_u64(vm); + uint64_t value = vm_pop_u64(vm); + local[0] = (uint32_t)(value >> 0); + local[1] = (uint32_t)(value >> 32); } break; - case Op_local_tee_32: - case Op_local_tee_64: { - uint64_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; pc->operand += 1; *local = vm->stack[vm->stack_top - 1]; } break; + case Op_local_tee_64: + { + uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; + pc->operand += 1; + local[0] = vm->stack[vm->stack_top - 2]; + local[1] = vm->stack[vm->stack_top - 1]; + } + break; case Op_global_get_0_32: - vm_push_u32(vm, vm->globals[0]); + vm_push_u32(vm, global_0); break; - case Op_global_get_32: { uint32_t idx = operands[pc->operand]; @@ -2896,11 +3214,9 @@ static void vm_run(struct VirtualMachine *vm) { vm_push_u32(vm, vm->globals[idx]); } break; - case Op_global_set_0_32: - vm->globals[0] = vm_pop_u32(vm); + global_0 = vm_pop_u32(vm); break; - case Op_global_set_32: { uint32_t idx = operands[pc->operand]; @@ -2909,1140 +3225,850 @@ static void vm_run(struct VirtualMachine *vm) { } break; - case Op_const_32: + case Op_load_0_8: { - uint32_t x = operands[pc->operand]; + uint32_t address = vm_pop_u32(vm); + vm_push_u32(vm, (uint8_t)vm->memory[address]); + } + break; + case Op_load_8: + { + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; pc->operand += 1; - vm_push_i32(vm, x); + vm_push_u32(vm, (uint8_t)vm->memory[address]); } break; - - case Op_const_64: + case Op_load_0_16: { - uint64_t x = ((uint64_t)operands[pc->operand]) | - (((uint64_t)operands[pc->operand + 1]) << 32); - pc->operand += 2; - vm_push_i64(vm, x); + uint32_t address = vm_pop_u32(vm); + vm_push_u32(vm, read_u16_le(&vm->memory[address])); } break; - - case Op_add_32: + case Op_load_16: { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs + rhs); + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + vm_push_u32(vm, read_u16_le(&vm->memory[address])); } break; - - case Op_and_32: + case Op_load_0_32: { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs & rhs); + uint32_t address = vm_pop_u32(vm); + vm_push_u32(vm, read_u32_le(&vm->memory[address])); } break; - - case Op_wasm: + case Op_load_32: { - enum WasmOp wasm_op = opcodes[pc->opcode]; - //fprintf(stderr, "op2=%x\n", wasm_op); - pc->opcode += 1; - switch (wasm_op) { - case WasmOp_unreachable: - case WasmOp_nop: - case WasmOp_block: - case WasmOp_loop: - case WasmOp_if: - case WasmOp_else: - case WasmOp_end: - case WasmOp_br: - case WasmOp_br_if: - case WasmOp_br_table: - case WasmOp_return: - case WasmOp_call: - case WasmOp_drop: - case WasmOp_select: - case WasmOp_local_get: - case WasmOp_local_set: - case WasmOp_local_tee: - case WasmOp_global_get: - case WasmOp_global_set: - case WasmOp_i32_const: - case WasmOp_i64_const: - case WasmOp_f32_const: - case WasmOp_f64_const: - case WasmOp_i32_add: - case WasmOp_i32_and: - case WasmOp_i32_reinterpret_f32: - case WasmOp_i64_reinterpret_f64: - case WasmOp_f32_reinterpret_i32: - case WasmOp_f64_reinterpret_i64: - case WasmOp_prefixed: - panic("not produced by decodeCode"); - break; - - case WasmOp_call_indirect: - { - uint32_t fn_id = vm->table[vm_pop_u32(vm)]; - vm_call(vm, fn_id); - } - break; - case WasmOp_i32_load: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_u32(vm, read_u32_le(vm->memory + offset)); - } - break; - case WasmOp_i64_load: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_u64(vm, read_u64_le(vm->memory + offset)); - } - break; - case WasmOp_f32_load: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - uint32_t integer = read_u32_le(vm->memory + offset); - vm_push_u32(vm, integer); - } - break; - case WasmOp_f64_load: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - uint64_t integer = read_u64_le(vm->memory + offset); - vm_push_u64(vm, integer); - } - break; - case WasmOp_i32_load8_s: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_i32(vm, (int8_t)vm->memory[offset]); - } - break; - case WasmOp_i32_load8_u: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_u32(vm, (uint8_t)vm->memory[offset]); - } - break; - case WasmOp_i32_load16_s: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - int16_t integer = read_i16_le(vm->memory + offset); - vm_push_i32(vm, integer); - } - break; - case WasmOp_i32_load16_u: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - uint16_t integer = read_u16_le(vm->memory + offset); - vm_push_u32(vm, integer); - } - break; - case WasmOp_i64_load8_s: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_i64(vm, (int8_t)vm->memory[offset]); - } - break; - case WasmOp_i64_load8_u: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm_push_u64(vm, (uint8_t)vm->memory[offset]); - } - break; - case WasmOp_i64_load16_s: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - int16_t integer = read_i16_le(vm->memory + offset); - vm_push_i64(vm, integer); - } - break; - case WasmOp_i64_load16_u: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - uint16_t integer = read_u16_le(vm->memory + offset); - vm_push_u64(vm, integer); - } - break; - case WasmOp_i64_load32_s: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - int32_t integer = read_i32_le(vm->memory + offset); - vm_push_i64(vm, integer); - } - break; - case WasmOp_i64_load32_u: - { - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - uint32_t integer = read_u32_le(vm->memory + offset); - vm_push_u64(vm, integer); - } - break; - case WasmOp_i32_store: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u32_le(vm->memory + offset, operand); - } - break; - case WasmOp_i64_store: - { - uint64_t operand = vm_pop_u64(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u64_le(vm->memory + offset, operand); - } - break; - case WasmOp_f32_store: - { - uint32_t integer = vm_pop_u32(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u32_le(vm->memory + offset, integer); - } - break; - case WasmOp_f64_store: - { - uint64_t integer = vm_pop_u64(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u64_le(vm->memory + offset, integer); - } - break; - case WasmOp_i32_store8: - { - uint8_t small = vm_pop_u32(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm->memory[offset] = small; - } - break; - case WasmOp_i32_store16: - { - uint16_t small = vm_pop_u32(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u16_le(vm->memory + offset, small); - } - break; - case WasmOp_i64_store8: - { - uint8_t operand = vm_pop_u64(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - vm->memory[offset] = operand; - } - break; - case WasmOp_i64_store16: - { - uint16_t small = vm_pop_u64(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u16_le(vm->memory + offset, small); - } - break; - case WasmOp_i64_store32: - { - uint32_t small = vm_pop_u64(vm); - uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); - pc->operand += 1; - write_u32_le(vm->memory + offset, small); - } - break; - case WasmOp_memory_size: - { - uint32_t page_count = vm->memory_len / wasm_page_size; - vm_push_u32(vm, page_count); - } - break; - case WasmOp_memory_grow: - { - uint32_t page_count = vm_pop_u32(vm); - uint32_t old_page_count = vm->memory_len / wasm_page_size; - uint32_t new_len = vm->memory_len + page_count * wasm_page_size; - if (new_len > max_memory) { - vm_push_i32(vm, -1); - } else { - vm->memory_len = new_len; - vm_push_u32(vm, old_page_count); - } - } - break; - case WasmOp_i32_eqz: - { - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs == 0); - } - break; - case WasmOp_i32_eq: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case WasmOp_i32_ne: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case WasmOp_i32_lt_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case WasmOp_i32_lt_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case WasmOp_i32_gt_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_i32_gt_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_i32_le_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_i32_le_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_i32_ge_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case WasmOp_i32_ge_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case WasmOp_i64_eqz: - { - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs == 0); - } - break; - case WasmOp_i64_eq: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case WasmOp_i64_ne: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case WasmOp_i64_lt_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case WasmOp_i64_lt_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case WasmOp_i64_gt_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_i64_gt_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_i64_le_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_i64_le_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_i64_ge_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case WasmOp_i64_ge_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case WasmOp_f32_eq: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case WasmOp_f32_ne: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case WasmOp_f32_lt: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case WasmOp_f32_gt: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_f32_le: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_f32_ge: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case WasmOp_f64_eq: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case WasmOp_f64_ne: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case WasmOp_f64_lt: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_f64_gt: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case WasmOp_f64_le: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case WasmOp_f64_ge: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + vm_push_u32(vm, read_u32_le(&vm->memory[address])); + } + break; + case Op_load_0_64: + { + uint32_t address = vm_pop_u32(vm); + vm_push_u64(vm, read_u64_le(&vm->memory[address])); + } + break; + case Op_load_64: + { + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + vm_push_u64(vm, read_u64_le(&vm->memory[address])); + } + break; + case Op_store_0_8: + { + uint8_t value = (uint8_t)vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm); + vm->memory[address] = value; + } + break; + case Op_store_8: + { + uint8_t value = (uint8_t)vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + vm->memory[address] = value; + } + break; + case Op_store_0_16: + { + uint16_t value = (uint16_t)vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm); + write_u16_le(&vm->memory[address], value); + } + break; + case Op_store_16: + { + uint16_t value = (uint16_t)vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + write_u16_le(&vm->memory[address], value); + } + break; + case Op_store_0_32: + { + uint32_t value = vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm); + write_u32_le(&vm->memory[address], value); + } + break; + case Op_store_32: + { + uint32_t value = vm_pop_u32(vm); + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + write_u32_le(&vm->memory[address], value); + } + break; + case Op_store_0_64: + { + uint64_t value = vm_pop_u64(vm); + uint32_t address = vm_pop_u32(vm); + write_u64_le(&vm->memory[address], value); + } + break; + case Op_store_64: + { + uint64_t value = vm_pop_u64(vm); + uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; + pc->operand += 1; + write_u64_le(&vm->memory[address], value); + } + break; + case Op_mem_size: + vm_push_u32(vm, vm->memory_len / wasm_page_size); + break; + case Op_mem_grow: + { + uint32_t page_count = vm_pop_u32(vm); + uint32_t old_page_count = vm->memory_len / wasm_page_size; + uint32_t new_len = vm->memory_len + page_count * wasm_page_size; + if (new_len > max_memory) { + vm_push_i32(vm, -1); + } else { + vm->memory_len = new_len; + vm_push_u32(vm, old_page_count); + } + } + break; - case WasmOp_i32_clz: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand); - vm_push_u32(vm, result); - } - break; - case WasmOp_i32_ctz: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand); - vm_push_u32(vm, result); - } - break; - case WasmOp_i32_popcnt: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = __builtin_popcount(operand); - vm_push_u32(vm, result); - } - break; - case WasmOp_i32_sub: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs - rhs); - } - break; - case WasmOp_i32_mul: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs * rhs); - } - break; - case WasmOp_i32_div_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs / rhs); - } - break; - case WasmOp_i32_div_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs / rhs); - } - break; - case WasmOp_i32_rem_s: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs % rhs); - } - break; - case WasmOp_i32_rem_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs % rhs); - } - break; - case WasmOp_i32_or: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs | rhs); - } - break; - case WasmOp_i32_xor: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs ^ rhs); - } - break; - case WasmOp_i32_shl: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs << (rhs & 0x1f)); - } - break; - case WasmOp_i32_shr_s: - { - uint32_t rhs = vm_pop_u32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs >> (rhs & 0x1f)); - } - break; - case WasmOp_i32_shr_u: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs >> (rhs & 0x1f)); - } - break; - case WasmOp_i32_rotl: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, rotl32(lhs, rhs)); - } - break; - case WasmOp_i32_rotr: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, rotr32(lhs, rhs )); - } - break; + case Op_const_0_32: + vm_push_i32(vm, 0); + break; + case Op_const_0_64: + vm_push_i64(vm, 0); + break; + case Op_const_1_32: + vm_push_i32(vm, 1); + break; + case Op_const_1_64: + vm_push_i64(vm, 1); + break; + case Op_const_32: + { + uint32_t value = operands[pc->operand]; + pc->operand += 1; + vm_push_i32(vm, value); + } + break; + case Op_const_64: + { + uint64_t value = ((uint64_t)operands[pc->operand]) | + (((uint64_t)operands[pc->operand + 1]) << 32); + pc->operand += 2; + vm_push_i64(vm, value); + } + break; + case Op_const_umax_32: + vm_push_i32(vm, -1); + break; + case Op_const_umax_64: + vm_push_i64(vm, -1); + break; - case WasmOp_i64_clz: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand); - vm_push_u64(vm, result); - } - break; - case WasmOp_i64_ctz: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand); - vm_push_u64(vm, result); - } - break; - case WasmOp_i64_popcnt: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = __builtin_popcountll(operand); - vm_push_u64(vm, result); - } - break; - case WasmOp_i64_add: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs + rhs); - } - break; - case WasmOp_i64_sub: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs - rhs); - } - break; - case WasmOp_i64_mul: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs * rhs); - } - break; - case WasmOp_i64_div_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs / rhs); - } - break; - case WasmOp_i64_div_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs / rhs); - } - break; - case WasmOp_i64_rem_s: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs % rhs); - } - break; - case WasmOp_i64_rem_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs % rhs); - } - break; - case WasmOp_i64_and: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs & rhs); - } - break; - case WasmOp_i64_or: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs | rhs); - } - break; - case WasmOp_i64_xor: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs ^ rhs); - } - break; - case WasmOp_i64_shl: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs << (rhs & 0x3f)); - } - break; - case WasmOp_i64_shr_s: - { - uint64_t rhs = vm_pop_u64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs >> (rhs & 0x3f)); - } - break; - case WasmOp_i64_shr_u: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs >> (rhs & 0x3f)); - } - break; - case WasmOp_i64_rotl: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotl64(lhs, rhs)); - } - break; - case WasmOp_i64_rotr: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotr64(lhs, rhs)); - } - break; + case Op_eqz_32: + { + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs == 0); + } + break; + case Op_eq_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case Op_ne_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case Op_slt_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case Op_ult_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case Op_sgt_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_ugt_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_sle_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_ule_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_sge_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case Op_uge_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; - case WasmOp_f32_abs: - { - vm_push_f32(vm, fabsf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_neg: - { - vm_push_f32(vm, -vm_pop_f32(vm)); - } - break; - case WasmOp_f32_ceil: - { - vm_push_f32(vm, ceilf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_floor: - { - vm_push_f32(vm, floorf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_trunc: - { - vm_push_f32(vm, truncf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_nearest: - { - vm_push_f32(vm, roundf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_sqrt: - { - vm_push_f32(vm, sqrtf(vm_pop_f32(vm))); - } - break; - case WasmOp_f32_add: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs + rhs); - } - break; - case WasmOp_f32_sub: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs - rhs); - } - break; - case WasmOp_f32_mul: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs * rhs); - } - break; - case WasmOp_f32_div: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs / rhs); - } - break; - case WasmOp_f32_min: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, (lhs < rhs) ? lhs : rhs); - } - break; - case WasmOp_f32_max: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, (lhs > rhs) ? lhs : rhs); - } - break; - case WasmOp_f32_copysign: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, copysignf(lhs, rhs)); - } - break; - case WasmOp_f64_abs: - { - vm_push_f64(vm, fabs(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_neg: - { - vm_push_f64(vm, -vm_pop_f64(vm)); - } - break; - case WasmOp_f64_ceil: - { - vm_push_f64(vm, ceil(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_floor: - { - vm_push_f64(vm, floor(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_trunc: - { - vm_push_f64(vm, trunc(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_nearest: - { - vm_push_f64(vm, round(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_sqrt: - { - vm_push_f64(vm, sqrt(vm_pop_f64(vm))); - } - break; - case WasmOp_f64_add: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs + rhs); - } - break; - case WasmOp_f64_sub: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs - rhs); - } - break; - case WasmOp_f64_mul: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs * rhs); - } - break; - case WasmOp_f64_div: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs / rhs); - } - break; - case WasmOp_f64_min: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, (lhs < rhs) ? lhs : rhs); - } - break; - case WasmOp_f64_max: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, (lhs > rhs) ? lhs : rhs); - } - break; - case WasmOp_f64_copysign: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, copysign(lhs, rhs)); - } - break; + case Op_eqz_64: + { + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs == 0); + } + break; + case Op_eq_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case Op_ne_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case Op_slt_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case Op_ult_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case Op_sgt_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_ugt_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_sle_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_ule_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_sge_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; + case Op_uge_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; - case WasmOp_i32_wrap_i64: - { - uint64_t operand = vm_pop_u64(vm); - vm_push_u32(vm, operand); - } - break; - case WasmOp_i32_trunc_f32_s: - { - float operand = vm_pop_f32(vm); - vm_push_i32(vm, truncf(operand)); - } - break; - case WasmOp_i32_trunc_f32_u: - { - float operand = vm_pop_f32(vm); - vm_push_u32(vm, truncf(operand)); - } - break; - case WasmOp_i32_trunc_f64_s: - { - double operand = vm_pop_f64(vm); - vm_push_i32(vm, trunc(operand)); - } - break; - case WasmOp_i32_trunc_f64_u: - { - double operand = vm_pop_f64(vm); - vm_push_u32(vm, trunc(operand)); - } - break; - case WasmOp_i64_extend_i32_s: - { - int32_t operand = vm_pop_i32(vm); - vm_push_i64(vm, operand); - } - break; - case WasmOp_i64_extend_i32_u: - { - uint64_t operand = vm_pop_u64(vm); - vm_push_u64(vm, operand); - } - break; - case WasmOp_i64_trunc_f32_s: - { - float operand = vm_pop_f32(vm); - vm_push_i64(vm, truncf(operand)); - } - break; - case WasmOp_i64_trunc_f32_u: - { - float operand = vm_pop_f32(vm); - vm_push_u64(vm, truncf(operand)); - } - break; - case WasmOp_i64_trunc_f64_s: - { - double operand = vm_pop_f64(vm); - vm_push_i64(vm, trunc(operand)); - } - break; - case WasmOp_i64_trunc_f64_u: - { - double operand = vm_pop_f64(vm); - vm_push_u64(vm, trunc(operand)); - } - break; - case WasmOp_f32_convert_i32_s: - { - vm_push_f32(vm, vm_pop_i32(vm)); - } - break; - case WasmOp_f32_convert_i32_u: - { - vm_push_f32(vm, vm_pop_u32(vm)); - } - break; - case WasmOp_f32_convert_i64_s: - { - vm_push_f32(vm, vm_pop_i64(vm)); - } - break; - case WasmOp_f32_convert_i64_u: - { - vm_push_f32(vm, vm_pop_u64(vm)); - } - break; - case WasmOp_f32_demote_f64: - { - vm_push_f32(vm, vm_pop_f64(vm)); - } - break; - case WasmOp_f64_convert_i32_s: - { - vm_push_f64(vm, vm_pop_i32(vm)); - } - break; - case WasmOp_f64_convert_i32_u: - { - vm_push_f64(vm, vm_pop_u32(vm)); - } - break; - case WasmOp_f64_convert_i64_s: - { - vm_push_f64(vm, vm_pop_i64(vm)); - } - break; - case WasmOp_f64_convert_i64_u: - { - vm_push_f64(vm, vm_pop_u64(vm)); - } - break; - case WasmOp_f64_promote_f32: - { - vm_push_f64(vm, vm_pop_f32(vm)); - } - break; + case Op_feq_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case Op_fne_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case Op_flt_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs < rhs); + } + break; + case Op_fgt_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_fle_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_fge_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; - case WasmOp_i32_extend8_s: - { - int8_t operand = vm_pop_i32(vm); - vm_push_i32(vm, operand); - } - break; - case WasmOp_i32_extend16_s: - { - int16_t operand = vm_pop_i32(vm); - vm_push_i32(vm, operand); - } - break; - case WasmOp_i64_extend8_s: - { - int8_t operand = vm_pop_i64(vm); - vm_push_i64(vm, operand); - } - break; - case WasmOp_i64_extend16_s: - { - int16_t operand = vm_pop_i64(vm); - vm_push_i64(vm, operand); - } - break; - case WasmOp_i64_extend32_s: - { - int32_t operand = vm_pop_i64(vm); - vm_push_i64(vm, operand); - } - break; + case Op_feq_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs == rhs); + } + break; + case Op_fne_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs != rhs); + } + break; + case Op_flt_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_fgt_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs > rhs); + } + break; + case Op_fle_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs <= rhs); + } + break; + case Op_fge_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_u32(vm, lhs >= rhs); + } + break; - default: - panic("unreachable"); - } + case Op_clz_32: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand); + vm_push_u32(vm, result); + } + break; + case Op_ctz_32: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand); + vm_push_u32(vm, result); + } + break; + case Op_popcnt_32: + { + uint32_t operand = vm_pop_u32(vm); + uint32_t result = __builtin_popcount(operand); + vm_push_u32(vm, result); + } + break; + case Op_add_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs + rhs); + } + break; + case Op_sub_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs - rhs); + } + break; + case Op_mul_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs * rhs); + } + break; + case Op_sdiv_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs / rhs); + } + break; + case Op_udiv_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs / rhs); + } + break; + case Op_srem_32: + { + int32_t rhs = vm_pop_i32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs % rhs); + } + break; + case Op_urem_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs % rhs); + } + break; + case Op_and_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs & rhs); + } + break; + case Op_or_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs | rhs); + } + break; + case Op_xor_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs ^ rhs); + } + break; + case Op_shl_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs << (rhs & 0x1f)); + } + break; + case Op_ashr_32: + { + uint32_t rhs = vm_pop_u32(vm); + int32_t lhs = vm_pop_i32(vm); + vm_push_i32(vm, lhs >> (rhs & 0x1f)); + } + break; + case Op_lshr_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, lhs >> (rhs & 0x1f)); + } + break; + case Op_rol_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, rotl32(lhs, rhs)); + } + break; + case Op_ror_32: + { + uint32_t rhs = vm_pop_u32(vm); + uint32_t lhs = vm_pop_u32(vm); + vm_push_u32(vm, rotr32(lhs, rhs)); } break; - case Op_wasm_prefixed: + case Op_clz_64: { - enum WasmPrefixedOp wasm_prefixed_op = opcodes[pc->opcode]; - pc->opcode += 1; - switch (wasm_prefixed_op) { - case WasmPrefixedOp_i32_trunc_sat_f32_s: - panic("unreachable"); - case WasmPrefixedOp_i32_trunc_sat_f32_u: - panic("unreachable"); - case WasmPrefixedOp_i32_trunc_sat_f64_s: - panic("unreachable"); - case WasmPrefixedOp_i32_trunc_sat_f64_u: - panic("unreachable"); - case WasmPrefixedOp_i64_trunc_sat_f32_s: - panic("unreachable"); - case WasmPrefixedOp_i64_trunc_sat_f32_u: - panic("unreachable"); - case WasmPrefixedOp_i64_trunc_sat_f64_s: - panic("unreachable"); - case WasmPrefixedOp_i64_trunc_sat_f64_u: - panic("unreachable"); - case WasmPrefixedOp_memory_init: - panic("unreachable"); - case WasmPrefixedOp_data_drop: - panic("unreachable"); - - case WasmPrefixedOp_memory_copy: - { - uint32_t n = vm_pop_u32(vm); - uint32_t src = vm_pop_u32(vm); - uint32_t dest = vm_pop_u32(vm); - assert(dest + n <= vm->memory_len); - assert(src + n <= vm->memory_len); - assert(src + n <= dest || dest + n <= src); // overlapping - memcpy(vm->memory + dest, vm->memory + src, n); - } - break; + uint64_t operand = vm_pop_u64(vm); + uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand); + vm_push_u64(vm, result); + } + break; + case Op_ctz_64: + { + uint64_t operand = vm_pop_u64(vm); + uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand); + vm_push_u64(vm, result); + } + break; + case Op_popcnt_64: + { + uint64_t operand = vm_pop_u64(vm); + uint64_t result = __builtin_popcountll(operand); + vm_push_u64(vm, result); + } + break; + case Op_add_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs + rhs); + } + break; + case Op_sub_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs - rhs); + } + break; + case Op_mul_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs * rhs); + } + break; + case Op_sdiv_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs / rhs); + } + break; + case Op_udiv_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs / rhs); + } + break; + case Op_srem_64: + { + int64_t rhs = vm_pop_i64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs % rhs); + } + break; + case Op_urem_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs % rhs); + } + break; + case Op_and_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs & rhs); + } + break; + case Op_or_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs | rhs); + } + break; + case Op_xor_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs ^ rhs); + } + break; + case Op_shl_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs << (rhs & 0x3f)); + } + break; + case Op_ashr_64: + { + uint64_t rhs = vm_pop_u64(vm); + int64_t lhs = vm_pop_i64(vm); + vm_push_i64(vm, lhs >> (rhs & 0x3f)); + } + break; + case Op_lshr_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, lhs >> (rhs & 0x3f)); + } + break; + case Op_rol_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, rotl64(lhs, rhs)); + } + break; + case Op_ror_64: + { + uint64_t rhs = vm_pop_u64(vm); + uint64_t lhs = vm_pop_u64(vm); + vm_push_u64(vm, rotr64(lhs, rhs)); + } + break; - case WasmPrefixedOp_memory_fill: - { - uint32_t n = vm_pop_u32(vm); - uint8_t value = vm_pop_u32(vm); - uint32_t dest = vm_pop_u32(vm); - assert(dest + n <= vm->memory_len); - memset(vm->memory + dest, value, n); - } - break; + case Op_fabs_32: + vm_push_f32(vm, fabsf(vm_pop_f32(vm))); + break; + case Op_fneg_32: + vm_push_f32(vm, -vm_pop_f32(vm)); + break; + case Op_ceil_32: + vm_push_f32(vm, ceilf(vm_pop_f32(vm))); + break; + case Op_floor_32: + vm_push_f32(vm, floorf(vm_pop_f32(vm))); + break; + case Op_trunc_32: + vm_push_f32(vm, truncf(vm_pop_f32(vm))); + break; + case Op_nearest_32: + vm_push_f32(vm, roundf(vm_pop_f32(vm))); + break; + case Op_sqrt_32: + vm_push_f32(vm, sqrtf(vm_pop_f32(vm))); + break; + case Op_fadd_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs + rhs); + } + break; + case Op_fsub_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs - rhs); + } + break; + case Op_fmul_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs * rhs); + } + break; + case Op_fdiv_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, lhs / rhs); + } + break; + case Op_fmin_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, fminf(lhs, rhs)); + } + break; + case Op_fmax_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, fmaxf(lhs, rhs)); + } + break; + case Op_copysign_32: + { + float rhs = vm_pop_f32(vm); + float lhs = vm_pop_f32(vm); + vm_push_f32(vm, copysignf(lhs, rhs)); + } + break; - case WasmPrefixedOp_table_init: panic("unreachable"); - case WasmPrefixedOp_elem_drop: panic("unreachable"); - case WasmPrefixedOp_table_copy: panic("unreachable"); - case WasmPrefixedOp_table_grow: panic("unreachable"); - case WasmPrefixedOp_table_size: panic("unreachable"); - case WasmPrefixedOp_table_fill: panic("unreachable"); - default: panic("unreachable"); - } + case Op_fabs_64: + vm_push_f64(vm, fabs(vm_pop_f64(vm))); + break; + case Op_fneg_64: + vm_push_f64(vm, -vm_pop_f64(vm)); + break; + case Op_ceil_64: + vm_push_f64(vm, ceil(vm_pop_f64(vm))); + break; + case Op_floor_64: + vm_push_f64(vm, floor(vm_pop_f64(vm))); + break; + case Op_trunc_64: + vm_push_f64(vm, trunc(vm_pop_f64(vm))); + break; + case Op_nearest_64: + vm_push_f64(vm, round(vm_pop_f64(vm))); + break; + case Op_sqrt_64: + vm_push_f64(vm, sqrt(vm_pop_f64(vm))); + break; + case Op_fadd_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs + rhs); + } + break; + case Op_fsub_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs - rhs); + } + break; + case Op_fmul_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs * rhs); + } + break; + case Op_fdiv_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, lhs / rhs); + } + break; + case Op_fmin_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, fmin(lhs, rhs)); + } + break; + case Op_fmax_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, fmax(lhs, rhs)); + } + break; + case Op_copysign_64: + { + double rhs = vm_pop_f64(vm); + double lhs = vm_pop_f64(vm); + vm_push_f64(vm, copysign(lhs, rhs)); } break; + case Op_ftos_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break; + case Op_ftou_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break; + case Op_ftos_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break; + case Op_ftou_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break; + case Op_sext_64_32: vm_push_i64(vm, vm_pop_i32(vm)); break; + case Op_ftos_64_32: vm_push_i64(vm, (int64_t)vm_pop_f32(vm)); break; + case Op_ftou_64_32: vm_push_u64(vm, (uint64_t)vm_pop_f32(vm)); break; + case Op_ftos_64_64: vm_push_i64(vm, (int64_t)vm_pop_f64(vm)); break; + case Op_ftou_64_64: vm_push_u64(vm, (uint64_t)vm_pop_f64(vm)); break; + case Op_stof_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break; + case Op_utof_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break; + case Op_stof_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break; + case Op_utof_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break; + case Op_ftof_32_64: vm_push_f32(vm, (float)vm_pop_f64(vm)); break; + case Op_stof_64_32: vm_push_f64(vm, (double)vm_pop_i32(vm)); break; + case Op_utof_64_32: vm_push_f64(vm, (double)vm_pop_u32(vm)); break; + case Op_stof_64_64: vm_push_f64(vm, (double)vm_pop_i64(vm)); break; + case Op_utof_64_64: vm_push_f64(vm, (double)vm_pop_u64(vm)); break; + case Op_ftof_64_32: vm_push_f64(vm, (double)vm_pop_f32(vm)); break; + case Op_sext8_32: vm_push_i32(vm, (int8_t)vm_pop_i32(vm)); break; + case Op_sext16_32: vm_push_i32(vm, (int16_t)vm_pop_i32(vm)); break; + case Op_sext8_64: vm_push_i64(vm, (int8_t)vm_pop_i64(vm)); break; + case Op_sext16_64: vm_push_i64(vm, (int16_t)vm_pop_i64(vm)); break; + case Op_sext32_64: vm_push_i64(vm, (int32_t)vm_pop_i64(vm)); break; + + case Op_memcpy: + { + uint32_t n = vm_pop_u32(vm); + uint32_t src = vm_pop_u32(vm); + uint32_t dest = vm_pop_u32(vm); + assert(dest + n <= vm->memory_len); + assert(src + n <= vm->memory_len); + assert(src + n <= dest || dest + n <= src); // overlapping + memcpy(vm->memory + dest, vm->memory + src, n); + } + break; + case Op_memset: + { + uint32_t n = vm_pop_u32(vm); + uint8_t value = (uint8_t)vm_pop_u32(vm); + uint32_t dest = vm_pop_u32(vm); + assert(dest + n <= vm->memory_len); + memset(vm->memory + dest, value, n); + } + break; } } } @@ -4064,11 +4090,12 @@ int main(int argc, char **argv) { size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path); const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len; + size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path); const char *new_argv[30]; char new_argv_buf[PATH_MAX + 1024]; - uint32_t new_argv_i = 0; + uint32_t new_argv_i = 0; uint32_t new_argv_buf_i = 0; int cache_dir = -1; @@ -4102,7 +4129,7 @@ int main(int argc, char **argv) { new_argv_i += 1; argv_i += 1; - for(; argv[argv_i]; argv_i += 1) { + for (; argv[argv_i]; argv_i += 1) { new_argv[new_argv_i] = argv[argv_i]; new_argv_i += 1; } @@ -4380,6 +4407,7 @@ int main(int argc, char **argv) { functions = arena_alloc(sizeof(struct Function) * functions_len); for (size_t func_i = 0; func_i < functions_len; func_i += 1) { struct Function *func = &functions[func_i]; + func->id = imports_len + func_i; func->type_idx = read32_uleb128(mod_ptr, &i); } } @@ -4474,7 +4502,7 @@ int main(int argc, char **argv) { #ifndef NDEBUG memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version #endif - vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), + vm.stack = arena_alloc(sizeof(uint32_t) * 10000000), vm.mod_ptr = mod_ptr; vm.opcodes = arena_alloc(2000000); vm.operands = arena_alloc(sizeof(uint32_t) * 2000000); @@ -4496,42 +4524,43 @@ int main(int argc, char **argv) { struct ProgramCounter pc; pc.opcode = 0; pc.operand = 0; + struct StackInfo stack; for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) { struct Function *func = &functions[func_i]; uint32_t size = read32_uleb128(mod_ptr, &code_i); uint32_t code_begin = code_i; + stack.top_index = 0; + stack.top_offset = 0; struct TypeInfo *type_info = &vm.types[func->type_idx]; - func->locals_count = 0; - func->local_types = malloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); - func->local_types[0] = type_info->param_types; + for (uint32_t param_i = 0; param_i < type_info->param_count; param_i += 1) + si_push(&stack, bs_isSet(&type_info->param_types, param_i)); + uint32_t params_size = stack.top_offset; for (uint32_t local_sets_count = read32_uleb128(mod_ptr, &code_i); local_sets_count > 0; local_sets_count -= 1) { - uint32_t set_count = read32_uleb128(mod_ptr, &code_i); - int64_t local_type = read64_ileb128(mod_ptr, &code_i); - - uint32_t i = type_info->param_count + func->locals_count; - func->locals_count += set_count; - if ((type_info->param_count + func->locals_count + 31) / 32 > (i + 31) / 32) - func->local_types = realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32)); - for (; i < type_info->param_count + func->locals_count; i += 1) - switch (local_type) { - case -1: case -3: bs_unset(func->local_types, i); break; - case -2: case -4: bs_set(func->local_types, i); break; - default: panic("unexpected local type"); - } + uint32_t local_set_count = read32_uleb128(mod_ptr, &code_i); + enum StackType local_type; + switch (read64_ileb128(mod_ptr, &code_i)) { + case -1: case -3: local_type = ST_32; break; + case -2: case -4: local_type = ST_64; break; + default: panic("unexpected local type"); + } + for (; local_set_count > 0; local_set_count -= 1) + si_push(&stack, local_type); } + func->locals_size = stack.top_offset - params_size; - //fprintf(stderr, "set up func %u with pc %u:%u\n", func->type_idx, pc.opcode, pc.operand); func->entry_pc = pc; - vm_decodeCode(&vm, func, &code_i, &pc); + //fprintf(stderr, "decoding func id %u with pc %u:%u\n", func->id, pc.opcode, pc.operand); + vm_decodeCode(&vm, type_info, &code_i, &pc, &stack); if (code_i != code_begin + size) panic("bad code size"); } + //fprintf(stderr, "%u opcodes\n%u operands\n", pc.opcode, pc.operand); } - vm_call(&vm, start_fn_idx); + vm_call(&vm, &vm.functions[start_fn_idx - imports_len]); vm_run(&vm); return 0; From 9cb06f3b8bf9ea6b5e5307711bc97328762d6a1d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Nov 2022 01:58:30 -0700 Subject: [PATCH 21/68] fix merge conflicts from master branch --- lib/std/fs/wasi.zig | 2 +- src/main.zig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index d15f37dc0fe7..fa9de0dff1e5 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -38,7 +38,7 @@ pub fn preopensAlloc(gpa: Allocator) Allocator.Error!Preopens { var prestat: prestat_t = undefined; switch (wasi.fd_prestat_get(fd, &prestat)) { .SUCCESS => {}, - .OPNOTSUPP, .BADF => return .{ .names = names.toOwnedSlice(gpa) }, + .OPNOTSUPP, .BADF => return .{ .names = try names.toOwnedSlice(gpa) }, else => @panic("fd_prestat_get: unexpected error"), } try names.ensureUnusedCapacity(gpa, 1); diff --git a/src/main.zig b/src/main.zig index c8ac670d10d1..c73e8acaf87b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3087,6 +3087,7 @@ fn buildOutputType( error.SemanticAnalyzeFail => if (!watch) process.exit(1), else => |e| return e, }; + if (build_options.only_c) return cleanExit(); try comp.makeBinFileExecutable(); if (test_exec_args.items.len == 0 and object_format == .c) default_exec_args: { From 906120bc2ce937e1dca047d1543b8caa7c843aea Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 27 Nov 2022 16:26:41 -0500 Subject: [PATCH 22/68] std.fmt: more descriptive names for impl functions This is a workaround for a limitation of the C backend. --- lib/std/fmt.zig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 6aac7386c97d..ac7f88ca9dec 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -827,7 +827,7 @@ fn formatSliceHexImpl(comptime case: Case) type { const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; return struct { - pub fn f( + pub fn formatSliceHexImpl( bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, @@ -846,8 +846,8 @@ fn formatSliceHexImpl(comptime case: Case) type { }; } -const formatSliceHexLower = formatSliceHexImpl(.lower).f; -const formatSliceHexUpper = formatSliceHexImpl(.upper).f; +const formatSliceHexLower = formatSliceHexImpl(.lower).formatSliceHexImpl; +const formatSliceHexUpper = formatSliceHexImpl(.upper).formatSliceHexImpl; /// Return a Formatter for a []const u8 where every byte is formatted as a pair /// of lowercase hexadecimal digits. @@ -865,7 +865,7 @@ fn formatSliceEscapeImpl(comptime case: Case) type { const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; return struct { - pub fn f( + pub fn formatSliceEscapeImpl( bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, @@ -891,8 +891,8 @@ fn formatSliceEscapeImpl(comptime case: Case) type { }; } -const formatSliceEscapeLower = formatSliceEscapeImpl(.lower).f; -const formatSliceEscapeUpper = formatSliceEscapeImpl(.upper).f; +const formatSliceEscapeLower = formatSliceEscapeImpl(.lower).formatSliceEscapeImpl; +const formatSliceEscapeUpper = formatSliceEscapeImpl(.upper).formatSliceEscapeImpl; /// Return a Formatter for a []const u8 where every non-printable ASCII /// character is escaped as \xNN, where NN is the character in lowercase @@ -910,7 +910,7 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap fn formatSizeImpl(comptime radix: comptime_int) type { return struct { - fn f( + fn formatSizeImpl( value: u64, comptime fmt: []const u8, options: FormatOptions, @@ -958,8 +958,8 @@ fn formatSizeImpl(comptime radix: comptime_int) type { }; } -const formatSizeDec = formatSizeImpl(1000).f; -const formatSizeBin = formatSizeImpl(1024).f; +const formatSizeDec = formatSizeImpl(1000).formatSizeImpl; +const formatSizeBin = formatSizeImpl(1024).formatSizeImpl; /// Return a Formatter for a u64 value representing a file size. /// This formatter represents the number as multiple of 1000 and uses the SI From ba8d5fc7f8c1fc574f94490d2b051abbc0f08b60 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Nov 2022 18:04:20 -0700 Subject: [PATCH 23/68] CMake: no optimization for zig1.c and zig2.c --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ebc876305cc..d196e1535b4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -713,8 +713,8 @@ if(MSVC) set(ZIG2_COMPILE_FLAGS "/std:c99") set(ZIG2_LINK_FLAGS "/STACK:16777216") else() - set(ZIG1_COMPILE_FLAGS "-std=c99 -O1") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O1") + set(ZIG1_COMPILE_FLAGS "-std=c99") + set(ZIG2_COMPILE_FLAGS "-std=c99") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() From 7ef745db59181654f90e2ad5b84c3cedf055635c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Nov 2022 19:35:18 -0700 Subject: [PATCH 24/68] Sema: queue type resolution for result of `@fieldParentPtr` --- src/Sema.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Sema.zig b/src/Sema.zig index cb6165f2f689..ecabd7b65edf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20951,6 +20951,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr } try sema.requireRuntimeBlock(block, src, ptr_src); + try sema.queueFullTypeResolution(result_ptr); return block.addInst(.{ .tag = .field_parent_ptr, .data = .{ .ty_pl = .{ From 02456a32ad6fa672ea383b57a2b9f592b9e2b9ed Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Dec 2022 00:49:55 -0700 Subject: [PATCH 25/68] CI: make Windows build from source like everybody else Now that OOM is no longer a problem, the Windows CI can do the same process every other system does instead of building from a recent Zig binary. --- CMakeLists.txt | 4 +-- ci/x86_64-windows.ps1 | 63 +++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d196e1535b4f..c91267bd4ae7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -769,9 +769,9 @@ target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib") target_link_libraries(zig2 LINK_PUBLIC zigcpp) if(MSVC) - target_link_libraries(zig2 ntdll.lib) + target_link_libraries(zig2 LINK_PUBLIC ntdll.lib) elseif(MINGW) - target_link_libraries(zig2 ntdll) + target_link_libraries(zig2 LINK_PUBLIC ntdll) endif() if(NOT MSVC) diff --git a/ci/x86_64-windows.ps1 b/ci/x86_64-windows.ps1 index 85195a85c3b8..641657b2c643 100644 --- a/ci/x86_64-windows.ps1 +++ b/ci/x86_64-windows.ps1 @@ -1,20 +1,17 @@ $TARGET = "$($Env:ARCH)-windows-gnu" $ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +$MCPU = "baseline" $ZIG_LLVM_CLANG_LLD_URL = "https://ziglang.org/deps/$ZIG_LLVM_CLANG_LLD_NAME.zip" +$PREFIX_PATH = "$(Get-Location)\$ZIG_LLVM_CLANG_LLD_NAME" +$ZIG = "$PREFIX_PATH\bin\zig.exe" Write-Output "Downloading $ZIG_LLVM_CLANG_LLD_URL" - Invoke-WebRequest -Uri "$ZIG_LLVM_CLANG_LLD_URL" -OutFile "$ZIG_LLVM_CLANG_LLD_NAME.zip" Write-Output "Extracting..." - -Add-Type -AssemblyName System.IO.Compression.FileSystem ; +Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD/$ZIG_LLVM_CLANG_LLD_NAME.zip", "$PWD") -Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib" -Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release" -Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$ZIG_LLVM_CLANG_LLD_NAME" - function CheckLastExitCode { if (!$?) { exit 1 @@ -31,33 +28,41 @@ if ((git rev-parse --is-shallow-repository) -eq "true") { git fetch --unshallow # `git describe` won't work on a shallow repo } -Write-Output "Building Zig..." - -& "$ZIGPREFIXPATH\bin\zig.exe" build ` - --prefix "$ZIGINSTALLDIR" ` - --search-prefix "$ZIGPREFIXPATH" ` - --zig-lib-dir "$ZIGLIBDIR" ` - -Denable-stage1 ` - -Dstatic-llvm ` - -Drelease ` - -Duse-zig-libcxx ` - -Dtarget="$TARGET" -CheckLastExitCode +Write-Output "Building from source..." +Remove-Item -Path 'build-release' -Recurse -Force -ErrorAction Ignore +New-Item -Path 'build-release' -ItemType Directory +Set-Location -Path 'build-release' -Write-Output " zig build test docs..." +# CMake gives a syntax error when file paths with backward slashes are used. +# Here, we use forward slashes only to work around this. +& cmake .. ` + -GNinja ` + -DCMAKE_INSTALL_PREFIX="stage3-release" ` + -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_C_COMPILER="$($ZIG -Replace "\\", "/");cc;-target;$TARGET;-mcpu=$MCPU" ` + -DCMAKE_CXX_COMPILER="$($ZIG -Replace "\\", "/");c++;-target;$TARGET;-mcpu=$MCPU" ` + -DZIG_TARGET_TRIPLE="$TARGET" ` + -DZIG_TARGET_MCPU="$MCPU" ` + -DZIG_STATIC=ON +CheckLastExitCode -& "$ZIGINSTALLDIR\bin\zig.exe" build test docs ` - --search-prefix "$ZIGPREFIXPATH" ` - -Dstatic-llvm ` - -Dskip-non-native ` - -Denable-symlinks-windows +ninja install CheckLastExitCode -# Produce the experimental std lib documentation. -Write-Output "zig test std/std.zig..." +Write-Output "Main test suite..." +& "stage3-release\bin\zig.exe" build test docs ` + --zig-lib-dir "..\lib" ` + --search-prefix "../$ZIG_LLVM_CLANG_LLD_NAME" ` + -Dstatic-llvm ` + -Dskip-non-native ` + -Denable-symlinks-windows +CheckLastExitCode -& "$ZIGINSTALLDIR\bin\zig.exe" test "$ZIGLIBDIR\std\std.zig" ` - --zig-lib-dir "$ZIGLIBDIR" ` +Write-Output "Testing Autodocs..." +& "stage3-release\bin\zig.exe" test "..\lib\std\std.zig" ` + --zig-lib-dir "..\lib" ` -femit-docs ` -fno-emit-bin CheckLastExitCode + From 9b8cf13c0023252f48bfc3542f38cafc424f83c6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Dec 2022 16:33:15 -0700 Subject: [PATCH 26/68] zig1.c: remove executable bit This was set on accident. --- stage1/zig1.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 stage1/zig1.c diff --git a/stage1/zig1.c b/stage1/zig1.c old mode 100755 new mode 100644 From fd54a014996e5a602eda26783ebe10589c58ecd1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Dec 2022 16:33:41 -0700 Subject: [PATCH 27/68] CMake: rebuild when the wasm blob changes --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c91267bd4ae7..6e9a0a3fac2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -725,11 +725,12 @@ target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") +set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(BUILD_ZIG2_ARGS "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_BINARY_DIR}" zig2 - "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" + "${ZIG1_WASM_ZST_SOURCE}" build-exe src/main.zig -ofmt=c -lc -OReleaseFast ) @@ -737,7 +738,7 @@ set(BUILD_ZIG2_ARGS add_custom_command( OUTPUT "${ZIG2_C_SOURCE}" COMMAND zig1 ${BUILD_ZIG2_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG2_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) @@ -755,7 +756,7 @@ set(BUILD_COMPILER_RT_ARGS add_custom_command( OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) From 7e151cb5e99101012872090480519be65573c9c1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Dec 2022 16:34:15 -0700 Subject: [PATCH 28/68] build: remove -Dwasi-bootstrap; add update-zig1 step Now it is a single command tdo update zig1.wasm.zst. --- build.zig | 91 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/build.zig b/build.zig index 675640ee1afb..f37fa9b2685d 100644 --- a/build.zig +++ b/build.zig @@ -14,17 +14,11 @@ const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 }; const stack_size = 32 * 1024 * 1024; pub fn build(b: *Builder) !void { - const wasi_bootstrap = b.option(bool, "wasi-bootstrap", "Produce a WASI build for bootstrapping the compiler") orelse false; - const release = b.option(bool, "release", "Build in release mode") orelse wasi_bootstrap; - const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse wasi_bootstrap; + const release = b.option(bool, "release", "Build in release mode") orelse false; + const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; const target = t: { var default_target: std.zig.CrossTarget = .{}; - if (wasi_bootstrap) { - default_target.cpu_arch = .wasm32; - default_target.os_tag = .wasi; - default_target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory)); - break :t default_target; - } else if (only_c) { + if (only_c) { default_target.ofmt = .c; } break :t b.standardTargetOptions(.{ .default_target = default_target }); @@ -81,7 +75,7 @@ pub fn build(b: *Builder) !void { if (deprecated_skip_install_lib_files) { std.log.warn("-Dskip-install-lib-files is deprecated in favor of -Dno-lib", .{}); } - const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files to installation prefix. Useful for development") orelse (deprecated_skip_install_lib_files or wasi_bootstrap); + const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files to installation prefix. Useful for development") orelse deprecated_skip_install_lib_files; const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; @@ -145,7 +139,7 @@ pub fn build(b: *Builder) !void { const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false; - const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or (only_c and !wasi_bootstrap)); + const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; const strip = b.option(bool, "strip", "Omit debug information"); const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; @@ -156,20 +150,17 @@ pub fn build(b: *Builder) !void { break :blk 4; }; - const main_file: ?[]const u8 = "src/main.zig"; - - const exe = b.addExecutable("zig", main_file); - - const compile_step = b.step("compile", "Build the self-hosted compiler"); - compile_step.dependOn(&exe.step); - - exe.stack_size = stack_size; + const exe = addCompilerStep(b); exe.strip = strip; exe.sanitize_thread = sanitize_thread; exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false; exe.install(); exe.setBuildMode(mode); exe.setTarget(target); + + const compile_step = b.step("compile", "Build the self-hosted compiler"); + compile_step.dependOn(&exe.step); + if (!skip_stage2_tests) { test_step.dependOn(&exe.step); } @@ -205,7 +196,7 @@ pub fn build(b: *Builder) !void { const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false; const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); - const version = if (opt_version_string) |version| version else v: { + const version_slice = if (opt_version_string) |version| version else v: { if (!std.process.can_spawn) { std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{}); std.process.exit(1); @@ -257,7 +248,8 @@ pub fn build(b: *Builder) !void { }, } }; - exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version)); + const version = try b.allocator.dupeZ(u8, version_slice); + exe_options.addOption([:0]const u8, "version", version); if (enable_llvm) { const cmake_cfg = if (static_llvm) null else blk: { @@ -347,7 +339,7 @@ pub fn build(b: *Builder) !void { test_cases_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2); test_cases_options.addOption(bool, "value_tracing", value_tracing); test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir); - test_cases_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version)); + test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption(std.SemanticVersion, "semver", semver); test_cases_options.addOption(?[]const u8, "test_filter", test_filter); @@ -465,6 +457,61 @@ pub fn build(b: *Builder) !void { skip_stage1, true, // TODO get these all passing )); + + try addWasiUpdateStep(b, version); +} + +fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { + const semver = try std.SemanticVersion.parse(version); + + var target: std.zig.CrossTarget = .{ + .cpu_arch = .wasm32, + .os_tag = .wasi, + }; + target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory)); + + const exe = addCompilerStep(b); + exe.setBuildMode(.ReleaseSmall); + exe.setTarget(target); + + const exe_options = b.addOptions(); + exe.addOptions("build_options", exe_options); + + exe_options.addOption(u32, "mem_leak_frames", 0); + exe_options.addOption(bool, "have_llvm", false); + exe_options.addOption(bool, "force_gpa", false); + exe_options.addOption(bool, "only_c", true); + exe_options.addOption([:0]const u8, "version", version); + exe_options.addOption(std.SemanticVersion, "semver", semver); + exe_options.addOption(bool, "enable_logging", false); + exe_options.addOption(bool, "enable_link_snapshots", false); + exe_options.addOption(bool, "enable_tracy", false); + exe_options.addOption(bool, "enable_tracy_callstack", false); + exe_options.addOption(bool, "enable_tracy_allocation", false); + exe_options.addOption(bool, "value_tracing", false); + + const run_opt = b.addSystemCommand(&.{ "wasm-opt", "-Oz", "--enable-bulk-memory" }); + run_opt.addArtifactArg(exe); + run_opt.addArg("-o"); + run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); + + const run_zstd = b.addSystemCommand(&.{ "zstd", "-19", "-f" }); + run_zstd.step.dependOn(&run_opt.step); + run_zstd.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); + run_zstd.addArg("-o"); + run_zstd.addFileSourceArg(.{ .path = "stage1/zig1.wasm.zst" }); + + const cleanup = b.addRemoveDirTree("stage1/zig1.wasm"); + cleanup.step.dependOn(&run_zstd.step); + + const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm.zst"); + update_zig1_step.dependOn(&cleanup.step); +} + +fn addCompilerStep(b: *Builder) *std.build.LibExeObjStep { + const exe = b.addExecutable("zig", "src/main.zig"); + exe.stack_size = stack_size; + return exe; } const exe_cflags = [_][]const u8{ From a63305bc5018afe538255218542e1d0af0393f01 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Dec 2022 14:21:35 -0700 Subject: [PATCH 29/68] CMake: use ReleaseSmall instead of ReleaseFast When producing C source code. This enables strip, which should avoid bloat and save compilation time. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e9a0a3fac2d..5365a291b2d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -732,7 +732,7 @@ set(BUILD_ZIG2_ARGS zig2 "${ZIG1_WASM_ZST_SOURCE}" build-exe src/main.zig -ofmt=c -lc - -OReleaseFast + -OReleaseSmall ) add_custom_command( @@ -750,7 +750,7 @@ set(BUILD_COMPILER_RT_ARGS compiler_rt "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-obj lib/compiler_rt.zig -ofmt=c - -OReleaseFast + -OReleaseSmall ) add_custom_command( From 12633467747de2349f7cc0f5068e9749801476b0 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 27 Nov 2022 19:55:12 -0500 Subject: [PATCH 30/68] use zig-wasm2c for bootstrapping --- CMakeLists.txt | 51 +- stage1/FuncGen.h | 164 ++ stage1/InputStream.h | 241 +++ stage1/panic.h | 12 + stage1/wasi.c | 948 +++++++++ stage1/wasm.h | 280 +++ stage1/wasm2c.c | 2520 +++++++++++++++++++++++ stage1/zig1.c | 4567 ------------------------------------------ 8 files changed, 4202 insertions(+), 4581 deletions(-) create mode 100644 stage1/FuncGen.h create mode 100644 stage1/InputStream.h create mode 100644 stage1/panic.h create mode 100644 stage1/wasi.c create mode 100644 stage1/wasm.h create mode 100644 stage1/wasm2c.c delete mode 100644 stage1/zig1.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5365a291b2d0..4bc2ae9dd4d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,8 +179,8 @@ set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std") set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h") set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") -set(STAGE1_SOURCES - "${CMAKE_SOURCE_DIR}/stage1/zig1.c" +set(ZIG_WASM2C_SOURCES + "${CMAKE_SOURCE_DIR}/stage1/wasm2c.c" "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/huf_decompress.c" "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_ddict.c" "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress.c" @@ -709,30 +709,53 @@ target_link_libraries(zigcpp LINK_PUBLIC ) if(MSVC) - set(ZIG1_COMPILE_FLAGS "/std:c99") - set(ZIG2_COMPILE_FLAGS "/std:c99") + set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2") + set(ZIG1_COMPILE_FLAGS "/std:c99 /Os") + set(ZIG2_COMPILE_FLAGS "/std:c99 /O0") set(ZIG2_LINK_FLAGS "/STACK:16777216") else() + set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99") set(ZIG2_COMPILE_FLAGS "-std=c99") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() -add_executable(zig1 ${STAGE1_SOURCES}) -set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) +string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}-${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_TRIPLE) +set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") +set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c") +set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") +set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") + +add_executable(zig-wasm2c ${ZIG_WASM2C_SOURCES}) +set_target_properties(zig-wasm2c PROPERTIES COMPILE_FLAGS ${ZIG_WASM2C_COMPILE_FLAGS}) +target_include_directories(zig-wasm2c PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") +target_compile_definitions(zig-wasm2c PRIVATE ZSTD_DISABLE_ASM) + +add_custom_command( + OUTPUT "${ZIG1_C_SOURCE}" + COMMAND zig-wasm2c "${ZIG1_WASM_SOURCE}" "${ZIG1_C_SOURCE}" + DEPENDS zig-wasm2c "${ZIG1_WASM_SOURCE}" + COMMENT STATUS "Converting ${ZIG1_WASM_SOURCE} to ${ZIG1_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) + +add_executable(zig1 ${ZIG1_C_SOURCE} "${CMAKE_SOURCE_DIR}/stage1/wasi.c") +set_target_properties(zig1 PROPERTIES + COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS} + LINK_FLAGS ${ZIG2_LINK_FLAGS}) target_link_libraries(zig1 LINK_PUBLIC m) target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) -set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(BUILD_ZIG2_ARGS "${CMAKE_SOURCE_DIR}/lib" - "${CMAKE_BINARY_DIR}" - zig2 - "${ZIG1_WASM_ZST_SOURCE}" build-exe src/main.zig -ofmt=c -lc -OReleaseSmall + --name zig2 -femit-bin="${ZIG2_C_SOURCE}" + --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end + -target "${HOST_TARGET_TRIPLE}" + --color on ) add_custom_command( @@ -743,14 +766,14 @@ add_custom_command( WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) -set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") set(BUILD_COMPILER_RT_ARGS "${CMAKE_SOURCE_DIR}/lib" - "${CMAKE_BINARY_DIR}" - compiler_rt - "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst" build-obj lib/compiler_rt.zig -ofmt=c -OReleaseSmall + --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}" + --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end + -target "${HOST_TARGET_TRIPLE}" + --color on ) add_custom_command( diff --git a/stage1/FuncGen.h b/stage1/FuncGen.h new file mode 100644 index 000000000000..11bd4198f0dd --- /dev/null +++ b/stage1/FuncGen.h @@ -0,0 +1,164 @@ +#ifndef FUNC_GEN_H +#define FUNC_GEN_H + +#include "panic.h" +#include "wasm.h" + +#include +#include +#include +#include +#include + +struct Block { + uint32_t type; + uint32_t label; + uint32_t stack_i; +}; + +struct FuncGen { + int8_t *type; + uint32_t *stack; + struct Block *block; + uint32_t type_i; + uint32_t stack_i; + uint32_t block_i; + uint32_t type_len; + uint32_t stack_len; + uint32_t block_len; +}; + +static void FuncGen_init(struct FuncGen *self) { + memset(self, 0, sizeof(struct FuncGen)); +} + +static void FuncGen_reset(struct FuncGen *self) { + self->type_i = 0; + self->stack_i = 0; + self->block_i = 0; +} + +static void FuncGen_free(struct FuncGen *self) { + free(self->block); + free(self->stack); + free(self->type); +} + +static void FuncGen_outdent(struct FuncGen *self, FILE *out) { + for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out); +} + +static void FuncGen_indent(struct FuncGen *self, FILE *out) { + FuncGen_outdent(self, out); + fputs(" ", out); +} + +static void FuncGen_cont(struct FuncGen *self, FILE *out) { + FuncGen_indent(self, out); + fputs(" ", out); +} + +static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) { + if (self->type_i == self->type_len) { + self->type_len += 10; + self->type_len *= 2; + self->type = realloc(self->type, sizeof(int8_t) * self->type_len); + if (self->type == NULL) panic("out of memory"); + } + uint32_t local_i = self->type_i; + self->type[local_i] = type; + self->type_i += 1; + return local_i; +} + +static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) { + uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type); + fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i); + return local_i; +} + +static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) { + return self->type[local_idx]; +} + +static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) { + if (self->stack_i == self->stack_len) { + self->stack_len += 10; + self->stack_len *= 2; + self->stack = realloc(self->stack, sizeof(uint32_t) * self->stack_len); + if (self->stack == NULL) panic("out of memory"); + } + FuncGen_indent(self, out); + fputs("const ", out); + self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type); + self->stack_i += 1; + fputs(" = ", out); +} + +static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx) { + return self->stack[self->stack_i - 1 - stack_idx]; +} + +static uint32_t FuncGen_stackPop(struct FuncGen *self) { + self->stack_i -= 1; + return self->stack[self->stack_i]; +} + +static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) { + FuncGen_indent(self, out); + fprintf(out, "goto l%" PRIu32 ";\n", label); + FuncGen_outdent(self, out); + fprintf(out, "l%" PRIu32 ":;\n", label); +} + +static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode kind, int64_t type) { + if (self->block_i == self->block_len) { + self->block_len += 10; + self->block_len *= 2; + self->block = realloc(self->block, sizeof(struct Block) * self->block_len); + if (self->block == NULL) panic("out of memory"); + } + uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind); + FuncGen_indent(self, out); + if (kind == WasmOpcode_if) fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(self)); + fputs("{\n", out); + self->block[self->block_i].type = type < 0 ? ~type : type; + self->block[self->block_i].label = label; + self->block[self->block_i].stack_i = self->stack_i; + self->block_i += 1; + if (kind == WasmOpcode_loop) FuncGen_label(self, out, label); +} + +static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) { + int8_t kind = self->type[self->block[self->block_i - 1 - label_idx].label]; + return (enum WasmOpcode)(kind < 0 ? ~kind : kind); +} + +static int64_t FuncGen_blockType(const struct FuncGen *self, uint32_t label_idx) { + struct Block *block = &self->block[self->block_i - 1 - label_idx]; + return self->type[block->label] < 0 ? ~(int64_t)block->type : (int64_t)block->type; +} + +static uint32_t FuncGen_blockLabel(const struct FuncGen *self, uint32_t label_idx) { + return self->block[self->block_i - 1 - label_idx].label; +} + +static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) { + enum WasmOpcode kind = FuncGen_blockKind(self, 0); + uint32_t label = FuncGen_blockLabel(self, 0); + if (kind != WasmOpcode_loop) FuncGen_label(self, out, label); + self->block_i -= 1; + FuncGen_indent(self, out); + fputs("}\n", out); + if (self->stack_i != self->block[self->block_i].stack_i) { + FuncGen_indent(self, out); + fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i); + } + self->stack_i = self->block[self->block_i].stack_i; +} + +static bool FuncGen_done(const struct FuncGen *self) { + return self->block_i == 0; +} + +#endif /* FUNC_GEN_H */ diff --git a/stage1/InputStream.h b/stage1/InputStream.h new file mode 100644 index 000000000000..36de3d6c7b81 --- /dev/null +++ b/stage1/InputStream.h @@ -0,0 +1,241 @@ +#ifndef INPUT_STREAM_H +#define INPUT_STREAM_H + +#include "panic.h" +#include "wasm.h" + +#include + +#include +#include +#include +#include +#include +#include + +struct InputStream { + FILE *stream; + ZSTD_DStream *ds; + ZSTD_outBuffer out; + ZSTD_inBuffer in; + size_t pos; +}; + +static void InputStream_open(struct InputStream *self, const char *path) { + self->stream = fopen(path, "rb"); + if (self->stream == NULL) panic("unable to open input file"); + self->ds = ZSTD_createDStream(); + if (self->ds == NULL) panic("unable to create zstd context"); + size_t in_size = ZSTD_initDStream(self->ds); + if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size)); + self->out.size = ZSTD_DStreamOutSize(); + self->out.dst = malloc(self->out.size + ZSTD_DStreamInSize()); + if (self->out.dst == NULL) panic("unable to allocate input buffers"); + self->out.pos = 0; + self->in.src = (const char *)self->out.dst + self->out.size; + self->in.size = fread((void *)self->in.src, 1, in_size, self->stream); + self->in.pos = 0; + self->pos = 0; +} + +static void InputStream_close(struct InputStream *self) { + free(self->out.dst); + ZSTD_freeDStream(self->ds); + fclose(self->stream); +} + +static bool InputStream_atEnd(struct InputStream *self) { + while (self->pos >= self->out.pos) { + self->out.pos = 0; + self->pos = 0; + size_t in_size = ZSTD_decompressStream(self->ds, &self->out, &self->in); + if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size)); + if (self->in.pos >= self->in.size) { + size_t max_in_size = ZSTD_DStreamInSize(); + if (in_size > max_in_size) in_size = max_in_size; + self->in.size = fread((void *)self->in.src, 1, in_size, self->stream); + self->in.pos = 0; + if (self->in.pos >= self->in.size) return true; + } + } + return false; +} + +static uint8_t InputStream_readByte(struct InputStream *self) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + uint8_t value = ((uint8_t *)self->out.dst)[self->pos]; + self->pos += 1; + return value; +} + +static uint32_t InputStream_readLittle_u32(struct InputStream *self) { + uint32_t value = 0; + value |= (uint32_t)InputStream_readByte(self) << 0; + value |= (uint32_t)InputStream_readByte(self) << 8; + value |= (uint32_t)InputStream_readByte(self) << 16; + value |= (uint32_t)InputStream_readByte(self) << 24; + return value; +} + +static uint64_t InputStream_readLittle_u64(struct InputStream *self) { + uint64_t value = 0; + value |= (uint64_t)InputStream_readByte(self) << 0; + value |= (uint64_t)InputStream_readByte(self) << 8; + value |= (uint64_t)InputStream_readByte(self) << 16; + value |= (uint64_t)InputStream_readByte(self) << 24; + value |= (uint64_t)InputStream_readByte(self) << 32; + value |= (uint64_t)InputStream_readByte(self) << 40; + value |= (uint64_t)InputStream_readByte(self) << 48; + value |= (uint64_t)InputStream_readByte(self) << 56; + return value; +} + +static float InputStream_readLittle_f32(struct InputStream *self) { + uint32_t value = InputStream_readLittle_u32(self); + float result; + memcpy(&result, &value, sizeof(result)); + return result; +} + +static double InputStream_readLittle_f64(struct InputStream *self) { + uint64_t value = InputStream_readLittle_u64(self); + double result; + memcpy(&result, &value, sizeof(result)); + return result; +} + +static uint32_t InputStream_readLeb128_u32(struct InputStream *self) { + uint32_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 32); + value |= (uint32_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + return value; +} + +static int32_t InputStream_readLeb128_i32(struct InputStream *self) { + uint32_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint32_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + if (shift < 32) { + uint32_t mask = -((uint32_t)1 << shift); + if (byte & 0x40) value |= mask; else value &= ~mask; + } + return (int32_t)value; +} + +static int64_t InputStream_readLeb128_u64(struct InputStream *self) { + uint64_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint64_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + return value; +} + +static int64_t InputStream_readLeb128_i64(struct InputStream *self) { + uint64_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint64_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + if (shift < 64) { + uint64_t mask = -((uint64_t)1 << shift); + if (byte & 0x40) value |= mask; else value &= ~mask; + } + return (int64_t)value; +} + +static char *InputStream_readName(struct InputStream *self) { + uint32_t len = InputStream_readLeb128_u32(self); + char *name = malloc(len + 1); + if (name == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; ) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + size_t remaining = self->out.pos - self->pos; + if (remaining > len - i) remaining = len - i; + memcpy(&name[i], &((char *)self->out.dst)[self->pos], remaining); + i += remaining; + self->pos += remaining; + } + name[len] = '\0'; + return name; +} + +static void InputStream_skipBytes(struct InputStream *self, size_t len) { + for (size_t i = 0; i < len; ) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + size_t remaining = self->out.pos - self->pos; + if (remaining > len - i) remaining = len - i; + i += remaining; + self->pos += remaining; + } +} + +static uint32_t InputStream_skipToSection(struct InputStream *self, uint8_t expected_id) { + while (true) { + uint8_t id = InputStream_readByte(self); + uint32_t size = InputStream_readLeb128_u32(self); + if (id == expected_id) return size; + InputStream_skipBytes(self, size); + } +} + +struct ResultType { + uint32_t len; + int8_t types[1]; +}; +static struct ResultType *InputStream_readResultType(struct InputStream *self) { + uint32_t len = InputStream_readLeb128_u32(self); + struct ResultType *result_type = malloc(offsetof(struct ResultType, types) + sizeof(int8_t) * len); + if (result_type == NULL) panic("out of memory"); + result_type->len = len; + for (uint32_t i = 0; i < len; i += 1) { + int64_t val_type = InputStream_readLeb128_i64(self); + switch (val_type) { + case WasmValType_i32: case WasmValType_i64: + case WasmValType_f32: case WasmValType_f64: + break; + + default: panic("unsupported valtype"); + } + result_type->types[i] = val_type; + } + return result_type; +} + +struct Limits { + uint32_t min; + uint32_t max; +}; +static struct Limits InputStream_readLimits(struct InputStream *self) { + struct Limits limits; + uint8_t kind = InputStream_readByte(self); + limits.min = InputStream_readLeb128_u32(self); + switch (kind) { + case 0x00: limits.max = UINT32_MAX; break; + case 0x01: limits.max = InputStream_readLeb128_u32(self); break; + default: panic("unsupported limit kind"); + } + return limits; +} + +#endif /* INPUT_STREAM_H */ diff --git a/stage1/panic.h b/stage1/panic.h new file mode 100644 index 000000000000..7a8fc5f45071 --- /dev/null +++ b/stage1/panic.h @@ -0,0 +1,12 @@ +#ifndef PANIC_H +#define PANIC_H + +#include +#include + +static void panic(const char *reason) { + fprintf(stderr, "%s\n", reason); + abort(); +} + +#endif /* PANIC_H */ diff --git a/stage1/wasi.c b/stage1/wasi.c new file mode 100644 index 000000000000..8ff04d5ef43f --- /dev/null +++ b/stage1/wasi.c @@ -0,0 +1,948 @@ +#include +#include +#include +#include +#include +#include + +#include "panic.h" + +#define LOG_TRACE 0 + +enum wasi_errno { + wasi_errno_success = 0, + wasi_errno_2big = 1, + wasi_errno_acces = 2, + wasi_errno_addrinuse = 3, + wasi_errno_addrnotavail = 4, + wasi_errno_afnosupport = 5, + wasi_errno_again = 6, + wasi_errno_already = 7, + wasi_errno_badf = 8, + wasi_errno_badmsg = 9, + wasi_errno_busy = 10, + wasi_errno_canceled = 11, + wasi_errno_child = 12, + wasi_errno_connaborted = 13, + wasi_errno_connrefused = 14, + wasi_errno_connreset = 15, + wasi_errno_deadlk = 16, + wasi_errno_destaddrreq = 17, + wasi_errno_dom = 18, + wasi_errno_dquot = 19, + wasi_errno_exist = 20, + wasi_errno_fault = 21, + wasi_errno_fbig = 22, + wasi_errno_hostunreach = 23, + wasi_errno_idrm = 24, + wasi_errno_ilseq = 25, + wasi_errno_inprogress = 26, + wasi_errno_intr = 27, + wasi_errno_inval = 28, + wasi_errno_io = 29, + wasi_errno_isconn = 30, + wasi_errno_isdir = 31, + wasi_errno_loop = 32, + wasi_errno_mfile = 33, + wasi_errno_mlink = 34, + wasi_errno_msgsize = 35, + wasi_errno_multihop = 36, + wasi_errno_nametoolong = 37, + wasi_errno_netdown = 38, + wasi_errno_netreset = 39, + wasi_errno_netunreach = 40, + wasi_errno_nfile = 41, + wasi_errno_nobufs = 42, + wasi_errno_nodev = 43, + wasi_errno_noent = 44, + wasi_errno_noexec = 45, + wasi_errno_nolck = 46, + wasi_errno_nolink = 47, + wasi_errno_nomem = 48, + wasi_errno_nomsg = 49, + wasi_errno_noprotoopt = 50, + wasi_errno_nospc = 51, + wasi_errno_nosys = 52, + wasi_errno_notconn = 53, + wasi_errno_notdir = 54, + wasi_errno_notempty = 55, + wasi_errno_notrecoverable = 56, + wasi_errno_notsock = 57, + wasi_errno_opnotsupp = 58, + wasi_errno_notty = 59, + wasi_errno_nxio = 60, + wasi_errno_overflow = 61, + wasi_errno_ownerdead = 62, + wasi_errno_perm = 63, + wasi_errno_pipe = 64, + wasi_errno_proto = 65, + wasi_errno_protonosupport = 66, + wasi_errno_prototype = 67, + wasi_errno_range = 68, + wasi_errno_rofs = 69, + wasi_errno_spipe = 70, + wasi_errno_srch = 71, + wasi_errno_stale = 72, + wasi_errno_timedout = 73, + wasi_errno_txtbsy = 74, + wasi_errno_xdev = 75, + wasi_errno_notcapable = 76, +}; + +enum wasi_oflags { + wasi_oflags_creat = 1 << 0, + wasi_oflags_directory = 1 << 1, + wasi_oflags_excl = 1 << 2, + wasi_oflags_trunc = 1 << 3, +}; + +enum wasi_rights { + wasi_rights_fd_datasync = 1ull << 0, + wasi_rights_fd_read = 1ull << 1, + wasi_rights_fd_seek = 1ull << 2, + wasi_rights_fd_fdstat_set_flags = 1ull << 3, + wasi_rights_fd_sync = 1ull << 4, + wasi_rights_fd_tell = 1ull << 5, + wasi_rights_fd_write = 1ull << 6, + wasi_rights_fd_advise = 1ull << 7, + wasi_rights_fd_allocate = 1ull << 8, + wasi_rights_path_create_directory = 1ull << 9, + wasi_rights_path_create_file = 1ull << 10, + wasi_rights_path_link_source = 1ull << 11, + wasi_rights_path_link_target = 1ull << 12, + wasi_rights_path_open = 1ull << 13, + wasi_rights_fd_readdir = 1ull << 14, + wasi_rights_path_readlink = 1ull << 15, + wasi_rights_path_rename_source = 1ull << 16, + wasi_rights_path_rename_target = 1ull << 17, + wasi_rights_path_filestat_get = 1ull << 18, + wasi_rights_path_filestat_set_size = 1ull << 19, + wasi_rights_path_filestat_set_times = 1ull << 20, + wasi_rights_fd_filestat_get = 1ull << 21, + wasi_rights_fd_filestat_set_size = 1ull << 22, + wasi_rights_fd_filestat_set_times = 1ull << 23, + wasi_rights_path_symlink = 1ull << 24, + wasi_rights_path_remove_directory = 1ull << 25, + wasi_rights_path_unlink_file = 1ull << 26, + wasi_rights_poll_fd_readwrite = 1ull << 27, + wasi_rights_sock_shutdown = 1ull << 28, + wasi_rights_sock_accept = 1ull << 29, +}; + +enum wasi_clockid { + wasi_clockid_realtime = 0, + wasi_clockid_monotonic = 1, + wasi_clockid_process_cputime_id = 2, + wasi_clockid_thread_cputime_id = 3, +}; + +enum wasi_filetype { + wasi_filetype_unknown = 0, + wasi_filetype_block_device = 1, + wasi_filetype_character_device = 2, + wasi_filetype_directory = 3, + wasi_filetype_regular_file = 4, + wasi_filetype_socket_dgram = 5, + wasi_filetype_socket_stream = 6, + wasi_filetype_symbolic_link = 7, +}; + +enum wasi_fdflags { + wasi_fdflags_append = 1 << 0, + wasi_fdflags_dsync = 1 << 1, + wasi_fdflags_nonblock = 1 << 2, + wasi_fdflags_rsync = 1 << 3, + wasi_fdflags_sync = 1 << 4, +}; + +struct wasi_filestat { + uint64_t dev; + uint64_t ino; + uint64_t filetype; + uint64_t nlink; + uint64_t size; + uint64_t atim; + uint64_t mtim; + uint64_t ctim; +}; + +struct wasi_fdstat { + uint16_t fs_filetype; + uint16_t fs_flags; + uint32_t padding; + uint64_t fs_rights_inheriting; +}; + +struct wasi_ciovec { + uint32_t ptr; + uint32_t len; +}; + +extern uint8_t **const wasm_memory; +extern void wasm__start(void); + +static int global_argc; +static char **global_argv; + +static uint32_t de_len; +struct DirEntry { + enum wasi_filetype filetype; + time_t atim; + time_t mtim; + time_t ctim; + char *guest_path; + char *host_path; +} *des; + +static uint32_t fd_len; +static struct FileDescriptor { + uint32_t de; + FILE *stream; +} *fds; + +static void *dupe(const void *data, size_t len) { + void *copy = malloc(len); + if (copy == NULL) panic("out of memory"); + memcpy(copy, data, len); + return copy; +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + global_argc = argc; + global_argv = argv; + + time_t now = time(NULL); + srand((unsigned)now); + + de_len = 4; + des = calloc(de_len, sizeof(struct DirEntry)); + if (des == NULL) panic("out of memory"); + + des[0].filetype = wasi_filetype_character_device; + + des[1].filetype = wasi_filetype_directory; + des[1].guest_path = dupe(".", sizeof(".")); + des[1].host_path = dupe(".", sizeof(".")); + + des[2].filetype = wasi_filetype_directory; + des[2].guest_path = dupe("/cache", sizeof("/cache")); + des[2].atim = now; + des[2].mtim = now; + des[2].ctim = now; + + des[3].filetype = wasi_filetype_directory; + des[3].guest_path = dupe("/lib", sizeof("/lib")); + des[3].host_path = dupe(argv[1], strlen(argv[1])); + + fd_len = 6; + fds = calloc(sizeof(struct FileDescriptor), fd_len); + if (fds == NULL) panic("out of memory"); + fds[0].stream = stdin; + fds[1].stream = stdout; + fds[2].stream = stderr; + fds[3].de = 1; + fds[4].de = 2; + fds[5].de = 3; + + wasm__start(); +} + +static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32_t path_len, enum wasi_filetype filetype, time_t tim, uint32_t *res_de) { + if (path[0] != '/') { + if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf; + if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + } + + struct DirEntry *new_des = realloc(des, (de_len + 1) * sizeof(struct DirEntry)); + if (new_des == NULL) return wasi_errno_nomem; + des = new_des; + + struct DirEntry *de = &des[de_len]; + de->filetype = filetype; + de->atim = tim; + de->mtim = tim; + de->ctim = tim; + if (path[0] == '/') { + de->guest_path = malloc(path_len + 1); + if (de->guest_path == NULL) return wasi_errno_nomem; + memcpy(&de->guest_path[0], path, path_len); + de->guest_path[path_len] = '\0'; + + de->host_path = malloc(path_len + 1); + if (de->host_path == NULL) return wasi_errno_nomem; + memcpy(&de->host_path[0], path, path_len); + de->host_path[path_len] = '\0'; + } else { + const struct DirEntry *dir_de = &des[fds[dir_fd].de]; + if (dir_de->guest_path != NULL) { + size_t dir_guest_path_len = strlen(dir_de->guest_path); + de->guest_path = malloc(dir_guest_path_len + 1 + path_len + 1); + if (de->guest_path == NULL) return wasi_errno_nomem; + memcpy(&de->guest_path[0], dir_de->guest_path, dir_guest_path_len); + de->guest_path[dir_guest_path_len] = '/'; + memcpy(&de->guest_path[dir_guest_path_len + 1], path, path_len); + de->guest_path[dir_guest_path_len + 1 + path_len] = '\0'; + } else de->guest_path = NULL; + + if (dir_de->host_path != NULL) { + size_t dir_host_path_len = strlen(dir_de->host_path); + de->host_path = malloc(dir_host_path_len + 1 + path_len + 1); + if (de->host_path == NULL) { free(de->guest_path); return wasi_errno_nomem; } + memcpy(&de->host_path[0], dir_de->host_path, dir_host_path_len); + de->host_path[dir_host_path_len] = '/'; + memcpy(&de->host_path[dir_host_path_len + 1], path, path_len); + de->host_path[dir_host_path_len + 1 + path_len] = '\0'; + } else de->host_path = NULL; + } + + if (res_de != NULL) *res_de = de_len; + de_len += 1; + return wasi_errno_success; +} + +static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) { + (void)flags; + if (path[0] == '/') { + for (uint32_t de = 0; de < de_len; de += 1) { + if (des[de].guest_path == NULL) continue; + if (memcmp(&des[de].guest_path[0], path, path_len) != 0) continue; + if (des[de].guest_path[path_len] != '\0') continue; + if (res_de != NULL) *res_de = de; + return wasi_errno_success; + } + } else { + if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf; + const struct DirEntry *dir_de = &des[fds[dir_fd].de]; + if (dir_de->filetype != wasi_filetype_directory) return wasi_errno_notdir; + + size_t dir_guest_path_len = strlen(dir_de->guest_path); + for (uint32_t de = 0; de < de_len; de += 1) { + if (des[de].guest_path == NULL) continue; + if (memcmp(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len) != 0) continue; + if (des[de].guest_path[dir_guest_path_len] != '/') continue; + if (memcmp(&des[de].guest_path[dir_guest_path_len + 1], path, path_len) != 0) continue; + if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue; + if (res_de != NULL) *res_de = de; + return wasi_errno_success; + } + } + return wasi_errno_noent; +} + +static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) { + res_filestat->dev = 0; + res_filestat->ino = de; + res_filestat->filetype = des[de].filetype; + res_filestat->nlink = 1; + res_filestat->size = 0; + res_filestat->atim = des[de].atim * UINT64_C(1000000000); + res_filestat->mtim = des[de].mtim * UINT64_C(1000000000); + res_filestat->ctim = des[de].ctim * UINT64_C(1000000000); +} + +static void DirEntry_unlink(uint32_t de) { + free(des[de].guest_path); + des[de].guest_path = NULL; + free(des[de].host_path); + des[de].host_path = NULL; +} + +uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv_buf_size) { + uint8_t *const m = *wasm_memory; + uint32_t *argv_size_ptr = (uint32_t *)&m[argv_size]; + uint32_t *argv_buf_size_ptr = (uint32_t *)&m[argv_buf_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_args_sizes_get()\n"); +#endif + + int c_argc = global_argc; + char **c_argv = global_argv; + uint32_t size = 0; + for (int i = 0; i < c_argc; i += 1) { + if (i == 1) continue; + size += strlen(c_argv[i]) + 1; + } + *argv_size_ptr = c_argc - 1; + *argv_buf_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) { + uint8_t *const m = *wasm_memory; + uint32_t *argv_ptr = (uint32_t *)&m[argv]; + char *argv_buf_ptr = (char *)&m[argv_buf]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_args_get()\n"); +#endif + + int c_argc = global_argc; + char **c_argv = global_argv; + uint32_t dst_i = 0; + uint32_t argv_buf_i = 0; + for (int src_i = 0; src_i < c_argc; src_i += 1) { + if (src_i == 1) continue; + argv_ptr[dst_i] = argv_buf + argv_buf_i; + dst_i += 1; + strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]); + argv_buf_i += strlen(c_argv[src_i]) + 1; + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat) { + uint8_t *const m = *wasm_memory; + uint32_t *res_prestat_ptr = (uint32_t *)&m[res_prestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_get(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + + res_prestat_ptr[0] = 0; + res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + char *path_ptr = (char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_dir_name(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + strncpy(path_ptr, des[fds[fd].de].guest_path, path_len); + return wasi_errno_success; +} + +void wasi_snapshot_preview1_proc_exit(uint32_t rval) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_proc_exit(%u)\n", rval); +#endif + + exit(rval); +} + +uint32_t wasi_snapshot_preview1_fd_close(uint32_t fd) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_close(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + if (fds[fd].stream != NULL) fclose(fds[fd].stream); + + fds[fd].de = ~0; + fds[fd].stream = NULL; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_create_directory(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_create_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, NULL); + switch (lookup_errno) { + case wasi_errno_success: return wasi_errno_exist; + case wasi_errno_noent: break; + default: return lookup_errno; + } + return DirEntry_create(fd, path_ptr, path_len, wasi_filetype_directory, time(NULL), NULL); +} + +uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_read(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t read_size = 0; + if (fds[fd].stream != NULL) + read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + panic("unimplemented"); + size += read_size; + if (read_size < iovs_ptr[i].len) break; + } + + if (size > 0) des[fds[fd].de].atim = time(NULL); + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filestat) { + uint8_t *const m = *wasm_memory; + struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_get(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + DirEntry_filestat(fds[fd].de, res_filestat_ptr); + if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_success; + if (fds[fd].stream == NULL) return wasi_errno_success; + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io; + long size = ftell(fds[fd].stream); + if (size < 0) return wasi_errno_io; + res_filestat_ptr->size = size; + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_rename(uint32_t fd, uint32_t old_path, uint32_t old_path_len, uint32_t new_fd, uint32_t new_path, uint32_t new_path_len) { + uint8_t *const m = *wasm_memory; + const char *old_path_ptr = (const char *)&m[old_path]; + const char *new_path_ptr = (const char *)&m[new_path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_rename(%u, \"%.*s\", %u, \"%.*s\")\n", fd, (int)old_path_len, old_path_ptr, new_fd, (int)new_path_len, new_path_ptr); +#endif + + uint32_t old_de; + enum wasi_errno old_lookup_errno = DirEntry_lookup(fd, 0, old_path_ptr, old_path_len, &old_de); + if (old_lookup_errno != wasi_errno_success) return old_lookup_errno; + DirEntry_unlink(old_de); + + uint32_t de; + enum wasi_errno new_lookup_errno = DirEntry_lookup(new_fd, 0, new_path_ptr, new_path_len, &de); + switch (new_lookup_errno) { + case wasi_errno_success: DirEntry_unlink(de); break; + case wasi_errno_noent: break; + default: return new_lookup_errno; + } + + uint32_t new_de; + enum wasi_errno create_errno = + DirEntry_create(new_fd, new_path_ptr, new_path_len, des[old_de].filetype, 0, &new_de); + if (create_errno != wasi_errno_success) return create_errno; + des[new_de].atim = des[old_de].atim; + des[new_de].mtim = des[old_de].mtim; + des[new_de].ctim = time(NULL); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_size(%u, %llu)\n", fd, (unsigned long long)size); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_inval; + + if (fds[fd].stream == NULL) return wasi_errno_success; + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io; + long old_size = ftell(fds[fd].stream); + if (old_size < 0) return wasi_errno_io; + if (size > (unsigned long)old_size) { + if (fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io; + fputc(0, fds[fd].stream); + } else if (size < (unsigned long)old_size) panic("unimplemented"); + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_pwrite(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io; + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t written_size = 0; + if (fds[fd].stream != NULL) + written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + written_size = iovs_ptr[i].len; + size += written_size; + if (written_size < iovs_ptr[i].len) break; + } + + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + + if (size > 0) { + time_t now = time(NULL); + des[fds[fd].de].atim = now; + des[fds[fd].de].mtim = now; + } + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_random_get(uint32_t buf, uint32_t buf_len) { + uint8_t *const m = *wasm_memory; + uint8_t *buf_ptr = (uint8_t *)&m[buf]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_random_get(%u)\n", buf_len); +#endif + + for (uint32_t i = 0; i < buf_len; i += 1) buf_ptr[i] = (uint8_t)rand(); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) { + (void)fd; + (void)atim; + (void)mtim; + (void)fst_flags; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_times(%u, %llu, %llu, 0x%X)\n", fd, (unsigned long long)atim, (unsigned long long)mtim, fst_flags); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_t environ_buf_size) { + (void)environ_size; + (void)environ_buf_size; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n"); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_buf) { + (void)environ; + (void)environ_buf; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n"); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, uint32_t path, uint32_t path_len, uint32_t res_filestat) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; + struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_filestat_get(%u, 0x%X, \"%.*s\")\n", fd, flags, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, flags, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + DirEntry_filestat(de, res_filestat_ptr); + if (des[de].filetype == wasi_filetype_regular_file && des[de].host_path != NULL) { + FILE *stream = fopen(des[de].host_path, "rb"); + if (stream != NULL) { + if (fseek(stream, 0, SEEK_END) >= 0) { + long size = ftell(stream); + if (size >= 0) res_filestat_ptr->size = size; + } + fclose(stream); + } + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat) { + (void)fd; + (void)res_fdstat; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_fdstat_get(%u)\n", fd); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t buf_len, uint64_t cookie, uint32_t res_size) { + (void)fd; + (void)buf; + (void)buf_len; + (void)cookie; + (void)res_size; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_write(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t written_size = 0; + if (fds[fd].stream != NULL) + written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + written_size = iovs_ptr[i].len; + size += written_size; + if (written_size < iovs_ptr[i].len) break; + } + + if (size > 0) { + time_t now = time(NULL); + des[fds[fd].de].atim = now; + des[fds[fd].de].mtim = now; + } + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32_t path, uint32_t path_len, uint32_t oflags, uint64_t fs_rights_base, uint64_t fs_rights_inheriting, uint32_t fdflags, uint32_t res_fd) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; + (void)fs_rights_inheriting; + uint32_t *res_fd_ptr = (uint32_t *)&m[res_fd]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_open(%u, 0x%X, \"%.*s\", 0x%X, 0x%llX, 0x%llX, 0x%X)\n", fd, dirflags, (int)path_len, path_ptr, oflags, (unsigned long long)fs_rights_base, (unsigned long long)fs_rights_inheriting, fdflags); +#endif + + bool creat = (oflags & wasi_oflags_creat) != 0; + bool directory = (oflags & wasi_oflags_directory) != 0; + bool excl = (oflags & wasi_oflags_excl) != 0; + bool trunc = (oflags & wasi_oflags_trunc) != 0; + bool append = (fdflags & wasi_fdflags_append) != 0; + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, dirflags, path_ptr, path_len, &de); + if (lookup_errno == wasi_errno_success) { + if (directory && des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + + struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor)); + if (new_fds == NULL) return wasi_errno_nomem; + fds = new_fds; + + fds[fd_len].de = de; + switch (des[de].filetype) { + case wasi_filetype_directory: fds[fd_len].stream = NULL; break; + default: panic("unimplemented"); + } + +#if LOG_TRACE + fprintf(stderr, "fd = %u\n", fd_len); +#endif + *res_fd_ptr = fd_len; + fd_len += 1; + } + if (lookup_errno != wasi_errno_noent) return lookup_errno; + + struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor)); + if (new_fds == NULL) return wasi_errno_nomem; + fds = new_fds; + + enum wasi_filetype filetype = directory ? wasi_filetype_directory : wasi_filetype_regular_file; + enum wasi_errno create_errno = DirEntry_create(fd, path_ptr, path_len, filetype, 0, &de); + if (create_errno != wasi_errno_success) return create_errno; + FILE *stream; + if (!directory) { + if (des[de].host_path == NULL) { + if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; } + time_t now = time(NULL); + des[de].atim = now; + des[de].mtim = now; + des[de].ctim = now; + stream = NULL; + } else { + if (oflags != (append ? wasi_oflags_creat : wasi_oflags_creat | wasi_oflags_trunc)) { + char mode[] = "rb+"; + if ((fs_rights_base & wasi_rights_fd_write) == 0) mode[2] = '\0'; + stream = fopen(des[de].host_path, mode); + if (stream != NULL) { + if (append || excl || trunc) fclose(stream); + if (excl) { + DirEntry_unlink(de); + de_len -= 1; + return wasi_errno_exist; + } + } else if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; } + } + if (append || trunc || stream == NULL) { + char mode[] = "wb+"; + if ((fs_rights_base & wasi_rights_fd_read) == 0) mode[2] = '\0'; + if (trunc || !append) { + stream = fopen(des[de].host_path, mode); + if (append && stream != NULL) fclose(stream); + } + if (append) { + mode[0] = 'a'; + stream = fopen(des[de].host_path, mode); + } + } + if (stream == NULL) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_isdir; } + } + } else stream = NULL; + +#if LOG_TRACE + fprintf(stderr, "fd = %u\n", fd_len); +#endif + fds[fd_len].de = de; + fds[fd_len].stream = stream; + *res_fd_ptr = fd_len; + fd_len += 1; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision, uint32_t res_timestamp) { + uint8_t *const m = *wasm_memory; + (void)precision; + uint64_t *res_timestamp_ptr = (uint64_t *)&m[res_timestamp]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_clock_time_get(%u, %llu)\n", id, (unsigned long long)precision); +#endif + + switch (id) { + case wasi_clockid_realtime: + *res_timestamp_ptr = time(NULL) * UINT64_C(1000000000); + break; + case wasi_clockid_monotonic: + case wasi_clockid_process_cputime_id: + case wasi_clockid_thread_cputime_id: + *res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC); + break; + default: return wasi_errno_inval; + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_remove_directory(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_remove_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + if (des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + DirEntry_unlink(de); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_unlink_file(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir; + if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented"); + DirEntry_unlink(de); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_pread(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io; + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t read_size = 0; + if (fds[fd].stream != NULL) + read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + panic("unimplemented"); + size += read_size; + if (read_size < iovs_ptr[i].len) break; + } + + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + + if (size > 0) des[fds[fd].de].atim = time(NULL); + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t nsubscriptions, uint32_t res_nevents) { + (void)in; + (void)out; + (void)nsubscriptions; + (void)res_nevents; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + + +void wasi_snapshot_preview1_debug(uint32_t string, uint64_t x) { + uint8_t *const m = *wasm_memory; + const char *string_ptr = (const char *)&m[string]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_debug(\"%s\", %llu, 0x%llX)\n", string_ptr, (unsigned long long)x, (unsigned long long)x); +#endif + + (void)string_ptr; + (void)x; +} diff --git a/stage1/wasm.h b/stage1/wasm.h new file mode 100644 index 000000000000..276d340bbbd2 --- /dev/null +++ b/stage1/wasm.h @@ -0,0 +1,280 @@ +#ifndef WASM_H +#define WASM_H + +#include "panic.h" + +enum WasmSectionId { + WasmSectionId_type = 1, + WasmSectionId_import = 2, + WasmSectionId_func = 3, + WasmSectionId_table = 4, + WasmSectionId_mem = 5, + WasmSectionId_global = 6, + WasmSectionId_export = 7, + WasmSectionId_start = 8, + WasmSectionId_elem = 9, + WasmSectionId_code = 10, + WasmSectionId_data = 11, + WasmSectionId_datacount = 12, +}; + +enum WasmValType { + WasmValType_i32 = -0x01, + WasmValType_i64 = -0x02, + WasmValType_f32 = -0x03, + WasmValType_f64 = -0x04, + WasmValType_v128 = -0x05, + WasmValType_funcref = -0x10, + WasmValType_externref = -0x11, + WasmValType_empty = -0x40, +}; +static const char *WasmValType_toC(enum WasmValType val_type) { + switch (val_type) { + case WasmValType_i32: return "uint32_t"; + case WasmValType_i64: return "uint64_t"; + case WasmValType_f32: return "float"; + case WasmValType_f64: return "double"; + case WasmValType_v128: panic("vector types are unsupported"); + case WasmValType_funcref: return "void (*)(void)"; + case WasmValType_externref: return "void *"; + default: panic("unsupported value type"); + } + return NULL; +} + +enum WasmMut { + WasmMut_const = 0x00, + WasmMut_var = 0x01, +}; +static const char *WasmMut_toC(enum WasmMut val_type) { + switch (val_type) { + case WasmMut_const: return "const "; + case WasmMut_var: return ""; + default: panic("unsupported mut"); + } +} + +enum WasmOpcode { + WasmOpcode_unreachable = 0x00, + WasmOpcode_nop = 0x01, + WasmOpcode_block = 0x02, + WasmOpcode_loop = 0x03, + WasmOpcode_if = 0x04, + WasmOpcode_else = 0x05, + WasmOpcode_end = 0x0B, + WasmOpcode_br = 0x0C, + WasmOpcode_br_if = 0x0D, + WasmOpcode_br_table = 0x0E, + WasmOpcode_return = 0x0F, + WasmOpcode_call = 0x10, + WasmOpcode_call_indirect = 0x11, + + WasmOpcode_drop = 0x1A, + WasmOpcode_select = 0x1B, + WasmOpcode_select_t = 0x1C, + + WasmOpcode_local_get = 0x20, + WasmOpcode_local_set = 0x21, + WasmOpcode_local_tee = 0x22, + WasmOpcode_global_get = 0x23, + WasmOpcode_global_set = 0x24, + + WasmOpcode_table_get = 0x25, + WasmOpcode_table_set = 0x26, + + WasmOpcode_i32_load = 0x28, + WasmOpcode_i64_load = 0x29, + WasmOpcode_f32_load = 0x2A, + WasmOpcode_f64_load = 0x2B, + WasmOpcode_i32_load8_s = 0x2C, + WasmOpcode_i32_load8_u = 0x2D, + WasmOpcode_i32_load16_s = 0x2E, + WasmOpcode_i32_load16_u = 0x2F, + WasmOpcode_i64_load8_s = 0x30, + WasmOpcode_i64_load8_u = 0x31, + WasmOpcode_i64_load16_s = 0x32, + WasmOpcode_i64_load16_u = 0x33, + WasmOpcode_i64_load32_s = 0x34, + WasmOpcode_i64_load32_u = 0x35, + WasmOpcode_i32_store = 0x36, + WasmOpcode_i64_store = 0x37, + WasmOpcode_f32_store = 0x38, + WasmOpcode_f64_store = 0x39, + WasmOpcode_i32_store8 = 0x3A, + WasmOpcode_i32_store16 = 0x3B, + WasmOpcode_i64_store8 = 0x3C, + WasmOpcode_i64_store16 = 0x3D, + WasmOpcode_i64_store32 = 0x3E, + WasmOpcode_memory_size = 0x3F, + WasmOpcode_memory_grow = 0x40, + + WasmOpcode_i32_const = 0x41, + WasmOpcode_i64_const = 0x42, + WasmOpcode_f32_const = 0x43, + WasmOpcode_f64_const = 0x44, + + WasmOpcode_i32_eqz = 0x45, + WasmOpcode_i32_eq = 0x46, + WasmOpcode_i32_ne = 0x47, + WasmOpcode_i32_lt_s = 0x48, + WasmOpcode_i32_lt_u = 0x49, + WasmOpcode_i32_gt_s = 0x4A, + WasmOpcode_i32_gt_u = 0x4B, + WasmOpcode_i32_le_s = 0x4C, + WasmOpcode_i32_le_u = 0x4D, + WasmOpcode_i32_ge_s = 0x4E, + WasmOpcode_i32_ge_u = 0x4F, + + WasmOpcode_i64_eqz = 0x50, + WasmOpcode_i64_eq = 0x51, + WasmOpcode_i64_ne = 0x52, + WasmOpcode_i64_lt_s = 0x53, + WasmOpcode_i64_lt_u = 0x54, + WasmOpcode_i64_gt_s = 0x55, + WasmOpcode_i64_gt_u = 0x56, + WasmOpcode_i64_le_s = 0x57, + WasmOpcode_i64_le_u = 0x58, + WasmOpcode_i64_ge_s = 0x59, + WasmOpcode_i64_ge_u = 0x5A, + + WasmOpcode_f32_eq = 0x5B, + WasmOpcode_f32_ne = 0x5C, + WasmOpcode_f32_lt = 0x5D, + WasmOpcode_f32_gt = 0x5E, + WasmOpcode_f32_le = 0x5F, + WasmOpcode_f32_ge = 0x60, + + WasmOpcode_f64_eq = 0x61, + WasmOpcode_f64_ne = 0x62, + WasmOpcode_f64_lt = 0x63, + WasmOpcode_f64_gt = 0x64, + WasmOpcode_f64_le = 0x65, + WasmOpcode_f64_ge = 0x66, + + WasmOpcode_i32_clz = 0x67, + WasmOpcode_i32_ctz = 0x68, + WasmOpcode_i32_popcnt = 0x69, + WasmOpcode_i32_add = 0x6A, + WasmOpcode_i32_sub = 0x6B, + WasmOpcode_i32_mul = 0x6C, + WasmOpcode_i32_div_s = 0x6D, + WasmOpcode_i32_div_u = 0x6E, + WasmOpcode_i32_rem_s = 0x6F, + WasmOpcode_i32_rem_u = 0x70, + WasmOpcode_i32_and = 0x71, + WasmOpcode_i32_or = 0x72, + WasmOpcode_i32_xor = 0x73, + WasmOpcode_i32_shl = 0x74, + WasmOpcode_i32_shr_s = 0x75, + WasmOpcode_i32_shr_u = 0x76, + WasmOpcode_i32_rotl = 0x77, + WasmOpcode_i32_rotr = 0x78, + + WasmOpcode_i64_clz = 0x79, + WasmOpcode_i64_ctz = 0x7A, + WasmOpcode_i64_popcnt = 0x7B, + WasmOpcode_i64_add = 0x7C, + WasmOpcode_i64_sub = 0x7D, + WasmOpcode_i64_mul = 0x7E, + WasmOpcode_i64_div_s = 0x7F, + WasmOpcode_i64_div_u = 0x80, + WasmOpcode_i64_rem_s = 0x81, + WasmOpcode_i64_rem_u = 0x82, + WasmOpcode_i64_and = 0x83, + WasmOpcode_i64_or = 0x84, + WasmOpcode_i64_xor = 0x85, + WasmOpcode_i64_shl = 0x86, + WasmOpcode_i64_shr_s = 0x87, + WasmOpcode_i64_shr_u = 0x88, + WasmOpcode_i64_rotl = 0x89, + WasmOpcode_i64_rotr = 0x8A, + + WasmOpcode_f32_abs = 0x8B, + WasmOpcode_f32_neg = 0x8C, + WasmOpcode_f32_ceil = 0x8D, + WasmOpcode_f32_floor = 0x8E, + WasmOpcode_f32_trunc = 0x8F, + WasmOpcode_f32_nearest = 0x90, + WasmOpcode_f32_sqrt = 0x91, + WasmOpcode_f32_add = 0x92, + WasmOpcode_f32_sub = 0x93, + WasmOpcode_f32_mul = 0x94, + WasmOpcode_f32_div = 0x95, + WasmOpcode_f32_min = 0x96, + WasmOpcode_f32_max = 0x97, + WasmOpcode_f32_copysign = 0x98, + + WasmOpcode_f64_abs = 0x99, + WasmOpcode_f64_neg = 0x9A, + WasmOpcode_f64_ceil = 0x9B, + WasmOpcode_f64_floor = 0x9C, + WasmOpcode_f64_trunc = 0x9D, + WasmOpcode_f64_nearest = 0x9E, + WasmOpcode_f64_sqrt = 0x9F, + WasmOpcode_f64_add = 0xA0, + WasmOpcode_f64_sub = 0xA1, + WasmOpcode_f64_mul = 0xA2, + WasmOpcode_f64_div = 0xA3, + WasmOpcode_f64_min = 0xA4, + WasmOpcode_f64_max = 0xA5, + WasmOpcode_f64_copysign = 0xA6, + + WasmOpcode_i32_wrap_i64 = 0xA7, + WasmOpcode_i32_trunc_f32_s = 0xA8, + WasmOpcode_i32_trunc_f32_u = 0xA9, + WasmOpcode_i32_trunc_f64_s = 0xAA, + WasmOpcode_i32_trunc_f64_u = 0xAB, + WasmOpcode_i64_extend_i32_s = 0xAC, + WasmOpcode_i64_extend_i32_u = 0xAD, + WasmOpcode_i64_trunc_f32_s = 0xAE, + WasmOpcode_i64_trunc_f32_u = 0xAF, + WasmOpcode_i64_trunc_f64_s = 0xB0, + WasmOpcode_i64_trunc_f64_u = 0xB1, + WasmOpcode_f32_convert_i32_s = 0xB2, + WasmOpcode_f32_convert_i32_u = 0xB3, + WasmOpcode_f32_convert_i64_s = 0xB4, + WasmOpcode_f32_convert_i64_u = 0xB5, + WasmOpcode_f32_demote_f64 = 0xB6, + WasmOpcode_f64_convert_i32_s = 0xB7, + WasmOpcode_f64_convert_i32_u = 0xB8, + WasmOpcode_f64_convert_i64_s = 0xB9, + WasmOpcode_f64_convert_i64_u = 0xBA, + WasmOpcode_f64_promote_f32 = 0xBB, + WasmOpcode_i32_reinterpret_f32 = 0xBC, + WasmOpcode_i64_reinterpret_f64 = 0xBD, + WasmOpcode_f32_reinterpret_i32 = 0xBE, + WasmOpcode_f64_reinterpret_i64 = 0xBF, + + WasmOpcode_i32_extend8_s = 0xC0, + WasmOpcode_i32_extend16_s = 0xC1, + WasmOpcode_i64_extend8_s = 0xC2, + WasmOpcode_i64_extend16_s = 0xC3, + WasmOpcode_i64_extend32_s = 0xC4, + + WasmOpcode_prefixed = 0xFC, +}; + +enum WasmPrefixedOpcode { + WasmPrefixedOpcode_i32_trunc_sat_f32_s = 0, + WasmPrefixedOpcode_i32_trunc_sat_f32_u = 1, + WasmPrefixedOpcode_i32_trunc_sat_f64_s = 2, + WasmPrefixedOpcode_i32_trunc_sat_f64_u = 3, + WasmPrefixedOpcode_i64_trunc_sat_f32_s = 4, + WasmPrefixedOpcode_i64_trunc_sat_f32_u = 5, + WasmPrefixedOpcode_i64_trunc_sat_f64_s = 6, + WasmPrefixedOpcode_i64_trunc_sat_f64_u = 7, + + WasmPrefixedOpcode_memory_init = 8, + WasmPrefixedOpcode_data_drop = 9, + WasmPrefixedOpcode_memory_copy = 10, + WasmPrefixedOpcode_memory_fill = 11, + + WasmPrefixedOpcode_table_init = 12, + WasmPrefixedOpcode_elem_drop = 13, + WasmPrefixedOpcode_table_copy = 14, + WasmPrefixedOpcode_table_grow = 15, + WasmPrefixedOpcode_table_size = 16, + WasmPrefixedOpcode_table_fill = 17, +}; + +#endif /* WASM_H */ diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c new file mode 100644 index 000000000000..1e0fb46bff7f --- /dev/null +++ b/stage1/wasm2c.c @@ -0,0 +1,2520 @@ +#include "FuncGen.h" +#include "InputStream.h" +#include "panic.h" +#include "wasm.h" + +#include +#include +#include +#include +#include +#include + +struct FuncType { + const struct ResultType *param; + const struct ResultType *result; +}; +static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) { + if (block_type >= 0) return &types[block_type]; + + static const struct ResultType none = { 0, { 0 }}; + static const struct ResultType i32 = { 1, { WasmValType_i32 } }; + static const struct ResultType i64 = { 1, { WasmValType_i64 } }; + static const struct ResultType f32 = { 1, { WasmValType_f32 } }; + static const struct ResultType f64 = { 1, { WasmValType_f64 } }; + + static const struct FuncType none_i32 = { &none, &i32 }; + static const struct FuncType none_i64 = { &none, &i64 }; + static const struct FuncType none_f32 = { &none, &f32 }; + static const struct FuncType none_f64 = { &none, &f64 }; + static const struct FuncType none_none = { &none, &none }; + + switch (block_type) { + case WasmValType_i32: return &none_i32; + case WasmValType_i64: return &none_i64; + case WasmValType_f32: return &none_f32; + case WasmValType_f64: return &none_f64; + case WasmValType_empty: return &none_none; + default: panic("unsupported block type"); + } + return NULL; +} + +static uint32_t evalExpr(struct InputStream *in) { + uint32_t value; + while (true) { + switch (InputStream_readByte(in)) { + case WasmOpcode_end: return value; + + case WasmOpcode_i32_const: + value = (uint32_t)InputStream_readLeb128_i32(in); + break; + + default: panic("unsupported expr opcode"); + } + } +} + +static void renderExpr(FILE *out, struct InputStream *in) { + while (true) { + switch (InputStream_readByte(in)) { + case WasmOpcode_end: return; + + case WasmOpcode_i32_const: { + uint32_t value = (uint32_t)InputStream_readLeb128_i32(in); + fprintf(out, "UINT32_C(0x%" PRIX32 ")", value); + break; + } + + default: panic("unsupported expr opcode"); + } + } +} + +int main(int argc, char **argv) { + if (argc != 3) { + fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]); + return 1; + } + + const char *mod = "wasm"; + bool isBigEndian = false; // TODO + + struct InputStream in; + InputStream_open(&in, argv[1]); + + if (InputStream_readByte(&in) != '\0' || + InputStream_readByte(&in) != 'a' || + InputStream_readByte(&in) != 's' || + InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file"); + if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version"); + + FILE *out = fopen(argv[2], "w"); + if (out == NULL) panic("unable to open output file"); + fputs("#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n" + "static uint32_t i32_reinterpret_f32(const float src) {\n" + " uint32_t dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static uint64_t i64_reinterpret_f64(const double src) {\n" + " uint64_t dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static float f32_reinterpret_i32(const uint32_t src) {\n" + " float dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static double f64_reinterpret_i64(const uint64_t src) {\n" + " double dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "\n" + "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t n) {\n" + " uint32_t r = *p;\n" + " uint32_t new_p = r + n;\n" + " uint8_t *new_m = realloc(*m, new_p << 16);\n" + " if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n" + " memset(&new_m[r << 16], 0, n << 16);\n" + " *m = new_m;\n" + " *p = new_p;\n" + " return r;\n" + "}\n" + "\n" + "static int inited;\n" + "static void init_elem(void);\n" + "static void init_data(void);\n" + "static void init(void) {\n" + " if (inited != 0) return;\n" + " init_elem();\n" + " init_data();\n" + " inited = 1;\n" + "}\n" + "\n", out); + + struct FuncType *types; + uint32_t max_param_len = 0; + (void)InputStream_skipToSection(&in, WasmSectionId_type); + { + uint32_t len = InputStream_readLeb128_u32(&in); + types = malloc(sizeof(struct FuncType) * len); + if (types == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + if (InputStream_readByte(&in) != 0x60) panic("expected functype"); + types[i].param = InputStream_readResultType(&in); + if (types[i].param->len > max_param_len) max_param_len = types[i].param->len; + types[i].result = InputStream_readResultType(&in); + } + } + + struct Import { + const char *mod; + const char *name; + uint32_t type_idx; + } *imports; + (void)InputStream_skipToSection(&in, WasmSectionId_import); + uint32_t imports_len = InputStream_readLeb128_u32(&in); + { + imports = malloc(sizeof(struct Import) * imports_len); + if (imports == NULL) panic("out of memory"); + for (uint32_t i = 0; i < imports_len; i += 1) { + imports[i].mod = InputStream_readName(&in); + imports[i].name = InputStream_readName(&in); + switch (InputStream_readByte(&in)) { + case 0x00: { // func + imports[i].type_idx = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[imports[i].type_idx]; + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " %s_%s(", imports[i].mod, imports[i].name); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fputs(WasmValType_toC(func_type->param->types[param_i]), out); + } + fputs(");\n", out); + break; + } + + case 0x01: // table + case 0x02: // mem + case 0x03: // global + default: + panic("unsupported import type"); + } + } + fputc('\n', out); + } + + struct Func { + uint32_t type_idx; + } *funcs; + (void)InputStream_skipToSection(&in, WasmSectionId_func); + { + uint32_t len = InputStream_readLeb128_u32(&in); + funcs = malloc(sizeof(struct Func) * len); + if (funcs == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + funcs[i].type_idx = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[funcs[i].type_idx]; + fputs("static ", out); + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " f%" PRIu32 "(", i); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i])); + } + fputs(");\n", out); + } + fputc('\n', out); + } + + struct Table { + int8_t type; + struct Limits limits; + } *tables; + (void)InputStream_skipToSection(&in, WasmSectionId_table); + { + uint32_t len = InputStream_readLeb128_u32(&in); + tables = malloc(sizeof(struct Table) * len); + if (tables == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + int64_t ref_type = InputStream_readLeb128_i64(&in); + switch (ref_type) { + case WasmValType_funcref: + break; + + default: panic("unsupported reftype"); + } + tables[i].type = ref_type; + tables[i].limits = InputStream_readLimits(&in); + if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported"); + fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n", + i, tables[i].limits.min); + } + fputc('\n', out); + } + + struct Mem { + struct Limits limits; + } *mems; + (void)InputStream_skipToSection(&in, WasmSectionId_mem); + uint32_t mems_len = InputStream_readLeb128_u32(&in); + { + mems = malloc(sizeof(struct Mem) * mems_len); + if (mems == NULL) panic("out of memory"); + for (uint32_t i = 0; i < mems_len; i += 1) { + mems[i].limits = InputStream_readLimits(&in); + fprintf(out, "static uint8_t *m%" PRIu32 ";\n" + "static uint32_t p%" PRIu32 ";\n", i, i); + } + fputc('\n', out); + } + + struct Global { + bool mut; + int8_t val_type; + } *globals; + (void)InputStream_skipToSection(&in, WasmSectionId_global); + { + uint32_t len = InputStream_readLeb128_u32(&in); + globals = malloc(sizeof(struct Global) * len); + if (globals == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + int64_t val_type = InputStream_readLeb128_i64(&in); + enum WasmMut mut = InputStream_readByte(&in); + fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i); + renderExpr(out, &in); + fputs(";\n", out); + globals[i].mut = mut; + globals[i].val_type = val_type; + } + fputc('\n', out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_export); + { + uint32_t len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < len; i += 1) { + char *name = InputStream_readName(&in); + uint8_t kind = InputStream_readByte(&in); + uint32_t idx = InputStream_readLeb128_u32(&in); + switch (kind) { + case 0x00: { + if (idx < imports_len) panic("can't export an import"); + const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx]; + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " %s_%s(", mod, name); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i); + } + fprintf(out, + ") {\n" + " init();\n" + " %sf%" PRIu32 "(", + func_type->result->len > 0 ? "return " : "", idx - imports_len); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "l%" PRIu32, param_i); + } + fputs(");\n}\n", out); + break; + } + + case 0x02: + fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx); + break; + + default: panic("unsupported export kind"); + } + free(name); + } + fputc('\n', out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_elem); + { + uint32_t table_i = 0; + uint32_t len = InputStream_readLeb128_u32(&in); + fputs("static void init_elem(void) {\n", out); + for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { + uint32_t table_idx = 0; + uint32_t elem_type = InputStream_readLeb128_u32(&in); + if (elem_type != 0x00) panic("unsupported elem type"); + uint32_t offset = evalExpr(&in); + uint32_t segment_len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < segment_len; i += 1) { + uint32_t func_id = InputStream_readLeb128_u32(&in); + fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&", + table_idx, offset + i); + if (func_id < imports_len) + fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name); + else + fprintf(out, "f%" PRIu32, func_id - imports_len); + fputs(";\n", out); + } + } + fputs("}\n\n", out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_code); + { + struct FuncGen fg; + FuncGen_init(&fg); + bool *param_used = malloc(sizeof(bool) * max_param_len); + uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len); + + uint32_t len = InputStream_readLeb128_u32(&in); + for (uint32_t func_i = 0; func_i < len; func_i += 1) { + FuncGen_reset(&fg); + + uint32_t code_len = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[funcs[func_i].type_idx]; + fputs("static ", out); + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " f%" PRIu32 "(", func_i); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + param_used[param_i] = false; + int8_t param_type = func_type->param->types[param_i]; + if (param_i > 0) fputs(", ", out); + FuncGen_localDeclare(&fg, out, param_type); + } + fputs(") {\n", out); + + for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in); + local_sets_remaining > 0; local_sets_remaining -= 1) { + uint32_t local_set_len = InputStream_readLeb128_u32(&in); + int64_t val_type = InputStream_readLeb128_i64(&in); + for (; local_set_len > 0; local_set_len -= 1) { + FuncGen_indent(&fg, out); + FuncGen_localDeclare(&fg, out, val_type); + fputs(" = 0;\n", out); + } + } + + uint32_t unreachable_depth = 0; + for (uint32_t result_i = func_type->result->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + (void)FuncGen_localDeclare(&fg, out, + func_type->result->types[result_i]); + fputs(";\n", out); + } + FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx); + while (!FuncGen_done(&fg)) { + //static const char *mnemonics[] = { + // [WasmOpcode_unreachable] = "unreachable", + // [WasmOpcode_nop] = "nop", + // [WasmOpcode_block] = "block", + // [WasmOpcode_loop] = "loop", + // [WasmOpcode_if] = "if", + // [WasmOpcode_else] = "else", + // [WasmOpcode_end] = "end", + // [WasmOpcode_br] = "br", + // [WasmOpcode_br_if] = "br_if", + // [WasmOpcode_br_table] = "br_table", + // [WasmOpcode_return] = "return", + // [WasmOpcode_call] = "call", + // [WasmOpcode_call_indirect] = "call_indirect", + // + // [WasmOpcode_drop] = "drop", + // [WasmOpcode_select] = "select", + // [WasmOpcode_select_t] = "select t", + // + // [WasmOpcode_local_get] = "local.get", + // [WasmOpcode_local_set] = "local.set", + // [WasmOpcode_local_tee] = "local.tee", + // [WasmOpcode_global_get] = "global.get", + // [WasmOpcode_global_set] = "global.set", + // [WasmOpcode_table_get] = "table.get", + // [WasmOpcode_table_set] = "table.set", + // + // [WasmOpcode_i32_load] = "i32.load", + // [WasmOpcode_i64_load] = "i64.load", + // [WasmOpcode_f32_load] = "f32.load", + // [WasmOpcode_f64_load] = "f64.load", + // [WasmOpcode_i32_load8_s] = "i32.load8_s", + // [WasmOpcode_i32_load8_u] = "i32.load8_u", + // [WasmOpcode_i32_load16_s] = "i32.load16_s", + // [WasmOpcode_i32_load16_u] = "i32.load16_u", + // [WasmOpcode_i64_load8_s] = "i64.load8_s", + // [WasmOpcode_i64_load8_u] = "i64.load8_u", + // [WasmOpcode_i64_load16_s] = "i64.load16_s", + // [WasmOpcode_i64_load16_u] = "i64.load16_u", + // [WasmOpcode_i64_load32_s] = "i64.load32_s", + // [WasmOpcode_i64_load32_u] = "i64.load32_u", + // [WasmOpcode_i32_store] = "i32.store", + // [WasmOpcode_i64_store] = "i64.store", + // [WasmOpcode_f32_store] = "f32.store", + // [WasmOpcode_f64_store] = "f64.store", + // [WasmOpcode_i32_store8] = "i32.store8", + // [WasmOpcode_i32_store16] = "i32.store16", + // [WasmOpcode_i64_store8] = "i64.store8", + // [WasmOpcode_i64_store16] = "i64.store16", + // [WasmOpcode_i64_store32] = "i64.store32", + // [WasmOpcode_memory_size] = "memory.size", + // [WasmOpcode_memory_grow] = "memory.grow", + // + // [WasmOpcode_i32_const] = "i32.const", + // [WasmOpcode_i64_const] = "i64.const", + // [WasmOpcode_f32_const] = "f32.const", + // [WasmOpcode_f64_const] = "f64.const", + // + // [WasmOpcode_i32_eqz] = "i32.eqz", + // [WasmOpcode_i32_eq] = "i32.eq", + // [WasmOpcode_i32_ne] = "i32.ne", + // [WasmOpcode_i32_lt_s] = "i32.lt_s", + // [WasmOpcode_i32_lt_u] = "i32.lt_u", + // [WasmOpcode_i32_gt_s] = "i32.gt_s", + // [WasmOpcode_i32_gt_u] = "i32.gt_u", + // [WasmOpcode_i32_le_s] = "i32.le_s", + // [WasmOpcode_i32_le_u] = "i32.le_u", + // [WasmOpcode_i32_ge_s] = "i32.ge_s", + // [WasmOpcode_i32_ge_u] = "i32.ge_u", + // + // [WasmOpcode_i64_eqz] = "i64.eqz", + // [WasmOpcode_i64_eq] = "i64.eq", + // [WasmOpcode_i64_ne] = "i64.ne", + // [WasmOpcode_i64_lt_s] = "i64.lt_s", + // [WasmOpcode_i64_lt_u] = "i64.lt_u", + // [WasmOpcode_i64_gt_s] = "i64.gt_s", + // [WasmOpcode_i64_gt_u] = "i64.gt_u", + // [WasmOpcode_i64_le_s] = "i64.le_s", + // [WasmOpcode_i64_le_u] = "i64.le_u", + // [WasmOpcode_i64_ge_s] = "i64.ge_s", + // [WasmOpcode_i64_ge_u] = "i64.ge_u", + // + // [WasmOpcode_f32_eq] = "f32.eq", + // [WasmOpcode_f32_ne] = "f32.ne", + // [WasmOpcode_f32_lt] = "f32.lt", + // [WasmOpcode_f32_gt] = "f32.gt", + // [WasmOpcode_f32_le] = "f32.le", + // [WasmOpcode_f32_ge] = "f32.ge", + // + // [WasmOpcode_f64_eq] = "f64.eq", + // [WasmOpcode_f64_ne] = "f64.ne", + // [WasmOpcode_f64_lt] = "f64.lt", + // [WasmOpcode_f64_gt] = "f64.gt", + // [WasmOpcode_f64_le] = "f64.le", + // [WasmOpcode_f64_ge] = "f64.ge", + // + // [WasmOpcode_i32_clz] = "i32.clz", + // [WasmOpcode_i32_ctz] = "i32.ctz", + // [WasmOpcode_i32_popcnt] = "i32.popcnt", + // [WasmOpcode_i32_add] = "i32.add", + // [WasmOpcode_i32_sub] = "i32.sub", + // [WasmOpcode_i32_mul] = "i32.mul", + // [WasmOpcode_i32_div_s] = "i32.div_s", + // [WasmOpcode_i32_div_u] = "i32.div_u", + // [WasmOpcode_i32_rem_s] = "i32.rem_s", + // [WasmOpcode_i32_rem_u] = "i32.rem_u", + // [WasmOpcode_i32_and] = "i32.and", + // [WasmOpcode_i32_or] = "i32.or", + // [WasmOpcode_i32_xor] = "i32.xor", + // [WasmOpcode_i32_shl] = "i32.shl", + // [WasmOpcode_i32_shr_s] = "i32.shr_s", + // [WasmOpcode_i32_shr_u] = "i32.shr_u", + // [WasmOpcode_i32_rotl] = "i32.rotl", + // [WasmOpcode_i32_rotr] = "i32.rotr", + // + // [WasmOpcode_i64_clz] = "i64.clz", + // [WasmOpcode_i64_ctz] = "i64.ctz", + // [WasmOpcode_i64_popcnt] = "i64.popcnt", + // [WasmOpcode_i64_add] = "i64.add", + // [WasmOpcode_i64_sub] = "i64.sub", + // [WasmOpcode_i64_mul] = "i64.mul", + // [WasmOpcode_i64_div_s] = "i64.div_s", + // [WasmOpcode_i64_div_u] = "i64.div_u", + // [WasmOpcode_i64_rem_s] = "i64.rem_s", + // [WasmOpcode_i64_rem_u] = "i64.rem_u", + // [WasmOpcode_i64_and] = "i64.and", + // [WasmOpcode_i64_or] = "i64.or", + // [WasmOpcode_i64_xor] = "i64.xor", + // [WasmOpcode_i64_shl] = "i64.shl", + // [WasmOpcode_i64_shr_s] = "i64.shr_s", + // [WasmOpcode_i64_shr_u] = "i64.shr_u", + // [WasmOpcode_i64_rotl] = "i64.rotl", + // [WasmOpcode_i64_rotr] = "i64.rotr", + // + // [WasmOpcode_f32_abs] = "f32.abs", + // [WasmOpcode_f32_neg] = "f32.neg", + // [WasmOpcode_f32_ceil] = "f32.ceil", + // [WasmOpcode_f32_floor] = "f32.floor", + // [WasmOpcode_f32_trunc] = "f32.trunc", + // [WasmOpcode_f32_nearest] = "f32.nearest", + // [WasmOpcode_f32_sqrt] = "f32.sqrt", + // [WasmOpcode_f32_add] = "f32.add", + // [WasmOpcode_f32_sub] = "f32.sub", + // [WasmOpcode_f32_mul] = "f32.mul", + // [WasmOpcode_f32_div] = "f32.div", + // [WasmOpcode_f32_min] = "f32.min", + // [WasmOpcode_f32_max] = "f32.max", + // [WasmOpcode_f32_copysign] = "f32.copysign", + // + // [WasmOpcode_f64_abs] = "f64.abs", + // [WasmOpcode_f64_neg] = "f64.neg", + // [WasmOpcode_f64_ceil] = "f64.ceil", + // [WasmOpcode_f64_floor] = "f64.floor", + // [WasmOpcode_f64_trunc] = "f64.trunc", + // [WasmOpcode_f64_nearest] = "f64.nearest", + // [WasmOpcode_f64_sqrt] = "f64.sqrt", + // [WasmOpcode_f64_add] = "f64.add", + // [WasmOpcode_f64_sub] = "f64.sub", + // [WasmOpcode_f64_mul] = "f64.mul", + // [WasmOpcode_f64_div] = "f64.div", + // [WasmOpcode_f64_min] = "f64.min", + // [WasmOpcode_f64_max] = "f64.max", + // [WasmOpcode_f64_copysign] = "f64.copysign", + // + // [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64", + // [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s", + // [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u", + // [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s", + // [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u", + // [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s", + // [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u", + // [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s", + // [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u", + // [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s", + // [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u", + // [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s", + // [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u", + // [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s", + // [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u", + // [WasmOpcode_f32_demote_f64] = "f32.demote_f64", + // [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s", + // [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u", + // [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s", + // [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u", + // [WasmOpcode_f64_promote_f32] = "f64.promote_f32", + // [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32", + // [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64", + // [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32", + // [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64", + // + // [WasmOpcode_i32_extend8_s] = "i32.extend8_s", + // [WasmOpcode_i32_extend16_s] = "i32.extend16_s", + // [WasmOpcode_i64_extend8_s] = "i64.extend8_s", + // [WasmOpcode_i64_extend16_s] = "i64.extend16_s", + // [WasmOpcode_i64_extend32_s] = "i64.extend32_s", + // + // [WasmOpcode_prefixed] = "prefixed", + //}; + uint8_t opcode = InputStream_readByte(&in); + //FuncGen_indent(&fg, out); + //fprintf(out, "// %2u: ", fg.stack_i); + //if (mnemonics[opcode]) + // fprintf(out, "%s\n", mnemonics[opcode]); + //else + // fprintf(out, "%02hhX\n", opcode); + //fflush(out); // DEBUG + switch (opcode) { + case WasmOpcode_unreachable: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "abort();\n"); + unreachable_depth += 1; + } + break; + case WasmOpcode_nop: + break; + case WasmOpcode_block: + case WasmOpcode_loop: + case WasmOpcode_if: { + int64_t block_type = InputStream_readLeb128_i64(&in); + if (unreachable_depth == 0) { + const struct FuncType *func_type = FuncType_blockType(types, block_type); + for (uint32_t param_i = func_type->param->len; param_i > 0; ) { + param_i -= 1; + FuncGen_indent(&fg, out); + param_stash[param_i] = + FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]); + fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + } + for (uint32_t result_i = func_type->result->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + (void)FuncGen_localDeclare(&fg, out, + func_type->result->types[result_i]); + fputs(";\n", out); + } + FuncGen_blockBegin(&fg, out, opcode, block_type); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + FuncGen_stackPush(&fg, out, func_type->param->types[param_i]); + fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]); + } + } else unreachable_depth += 1; + break; + } + case WasmOpcode_else: + case WasmOpcode_end: + if (unreachable_depth <= 1) { + const struct ResultType *result_type = + FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result; + uint32_t label = FuncGen_blockLabel(&fg, 0); + if (unreachable_depth == 0) { + const struct ResultType *result_type = + FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result; + for (uint32_t result_i = result_type->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + label - result_type->len + result_i, FuncGen_stackPop(&fg)); + } + } else unreachable_depth -= 1; + switch (opcode) { + case WasmOpcode_else: + FuncGen_outdent(&fg, out); + fputs("} else {\n", out); + break; + case WasmOpcode_end: + FuncGen_blockEnd(&fg, out); + for (uint32_t result_i = 0; result_i < result_type->len; + result_i += 1) { + FuncGen_stackPush(&fg, out, result_type->types[result_i]); + fprintf(out, "l%" PRIu32 ";\n", + label - result_type->len + result_i); + } + break; + } + } else if (opcode == WasmOpcode_end) unreachable_depth -= 1; + break; + case WasmOpcode_br: + case WasmOpcode_br_if: { + uint32_t label_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx); + const struct FuncType *func_type = + FuncType_blockType(types, FuncGen_blockType(&fg, label_idx)); + uint32_t label = FuncGen_blockLabel(&fg, label_idx); + + FuncGen_indent(&fg, out); + if (opcode == WasmOpcode_br_if) + fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(&fg)); + fputs("{\n", out); + const struct ResultType *label_type; + uint32_t lhs; + switch (kind) { + case WasmOpcode_loop: + label_type = func_type->param; + lhs = label - func_type->result->len - func_type->param->len; + break; + default: + label_type = func_type->result; + lhs = label - func_type->result->len; + break; + } + for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) { + uint32_t rhs; + switch (opcode) { + case WasmOpcode_br: + rhs = FuncGen_stackPop(&fg); + break; + case WasmOpcode_br_if: + rhs = FuncGen_stackAt(&fg, stack_i); + break; + default: panic("unexpected opcode"); + } + FuncGen_cont(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs); + lhs += 1; + } + FuncGen_cont(&fg, out); + fprintf(out, "goto l%" PRIu32 ";\n", label); + FuncGen_indent(&fg, out); + fprintf(out, "}\n"); + if (opcode == WasmOpcode_br) unreachable_depth += 1; + } + break; + } + case WasmOpcode_br_table: { + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg)); + } + uint32_t label_len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < label_len; i += 1) { + uint32_t label = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "case %u: goto l%" PRIu32 ";\n", + i, FuncGen_blockLabel(&fg, label)); + } + } + uint32_t label = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "default: goto l%" PRIu32 ";\n", + FuncGen_blockLabel(&fg, label)); + FuncGen_indent(&fg, out); + fputs("}\n", out); + unreachable_depth += 1; + } + break; + } + case WasmOpcode_return: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fputs("return", out); + switch (func_type->result->len) { + case 0: break; + case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break; + default: panic("multiple function returns not supported"); + } + fputs(";\n", out); + unreachable_depth += 1; + } + break; + case WasmOpcode_call: + case WasmOpcode_call_indirect: { + uint32_t func_id; + uint32_t type_idx; + uint32_t table_idx; + switch (opcode) { + case WasmOpcode_call: + func_id = InputStream_readLeb128_u32(&in); + if (func_id < imports_len) + type_idx = imports[func_id].type_idx; + else + type_idx = funcs[func_id - imports_len].type_idx; + break; + case WasmOpcode_call_indirect: + type_idx = InputStream_readLeb128_u32(&in); + table_idx = InputStream_readLeb128_u32(&in); + func_id = FuncGen_stackPop(&fg); + break; + } + if (unreachable_depth == 0) { + const struct FuncType *callee_func_type = &types[type_idx]; + for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) { + param_i -= 1; + param_stash[param_i] = FuncGen_stackPop(&fg); + } + switch (callee_func_type->result->len) { + case 0: FuncGen_indent(&fg, out); break; + case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break; + default: panic("multiple function returns not supported"); + } + switch (opcode) { + case WasmOpcode_call: + if (func_id < imports_len) + fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name); + else + fprintf(out, "f%" PRIu32, func_id - imports_len); + break; + case WasmOpcode_call_indirect: + fputs("(*(", out); + switch (callee_func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fputs(" (*)(", out); + if (callee_func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out); + } + fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id); + break; + } + fputc('(', out); + for (uint32_t param_i = 0; param_i < callee_func_type->param->len; + param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "l%" PRIu32, param_stash[param_i]); + } + fputs(");\n", out); + } + break; + } + + case WasmOpcode_drop: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + } + break; + case WasmOpcode_select: + if (unreachable_depth == 0) { + uint32_t cond = FuncGen_stackPop(&fg); + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, lhs)); + fprintf(out, "l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n", + cond, lhs, rhs); + } + break; + + case WasmOpcode_local_get: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx)); + fprintf(out, "l%" PRIu32 ";\n", local_idx); + } + break; + } + case WasmOpcode_local_set: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + local_idx, FuncGen_stackPop(&fg)); + } + break; + } + case WasmOpcode_local_tee: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + local_idx, FuncGen_stackAt(&fg, 0)); + } + break; + } + + case WasmOpcode_global_get: { + uint32_t global_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, globals[global_idx].val_type); + fprintf(out, "g%" PRIu32 ";\n", global_idx); + } + break; + } + case WasmOpcode_global_set: { + uint32_t global_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n", + global_idx, FuncGen_stackPop(&fg)); + } + break; + } + + case WasmOpcode_table_get: + case WasmOpcode_table_set: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + break; + + case WasmOpcode_i32_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + if (align < 2 || isBigEndian) { + fseek(out, -1, SEEK_CUR); + fputc('\n', out); + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i64_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + if (align < 3 || isBigEndian) { + fseek(out, -1, SEEK_CUR); + fputc('\n', out); + for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + } else fprintf(out, "*(const uint64_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_f32_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + if (align < 2 || isBigEndian) { + fputs("f32_reinterpret_i32(\n", out); + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + fputc(')', out); + } else fprintf(out, "*(const float *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_f64_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + if (align < 3 || isBigEndian) { + fputs("f64_reinterpret_i64(\n", out); + for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + fputc(')', out); + } else fprintf(out, "*(const double *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i32_load8_s: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i32_load8_u: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i32_load16_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + if (align < 1 || isBigEndian) { + fputs("(int16_t)(\n", out); + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + fputc(')', out); + } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i32_load16_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + if (align < 1 || isBigEndian) { + fseek(out, -1, SEEK_CUR); + fputc('\n', out); + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i64_load8_s: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i64_load8_u: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i64_load16_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + if (align < 1 || isBigEndian) { + fputs("(int16_t)(\n", out); + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + fputc(')', out); + } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i64_load16_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + if (align < 1 || isBigEndian) { + fseek(out, -1, SEEK_CUR); + fputc('\n', out); + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i64_load32_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + if (align < 2 || isBigEndian) { + fputs("(int32_t)(\n", out); + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + fputc(')', out); + } else fprintf(out, "*(const int32_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + case WasmOpcode_i64_load32_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + if (align < 2 || isBigEndian) { + fseek(out, -1, SEEK_CUR); + fputc('\n', out); + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + if (byte_i > 0) fputs(" |\n", out); + FuncGen_cont(&fg, out); + fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" + PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); + } + } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")]", 0, base, offset); + fputs(";\n", out); + } + break; + } + + case WasmOpcode_i32_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 2 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(l%" PRIu32 " >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_i64_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 3 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(l%" PRIu32 " >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(uint64_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_f32_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 2 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(i32_reinterpret_f32(l%" PRIu32 ") >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(float *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_f64_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 3 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(i64_reinterpret_f64(l%" PRIu32 ") >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(double *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_i32_store8: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 + ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value); + } + break; + } + case WasmOpcode_i32_store16: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 1 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(l%" PRIu32 " >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_i64_store8: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 + ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value); + } + break; + } + case WasmOpcode_i64_store16: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 1 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(l%" PRIu32 " >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + case WasmOpcode_i64_store32: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + if (align < 2 || isBigEndian) { + for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " + "(uint8_t)(l%" PRIu32 " >> %2u);\n", + 0, base, offset + byte_i, value, byte_i << 3); + } + } else { + FuncGen_indent(&fg, out); + fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32 + " + UINT32_C(%" PRIu32 ")] = (uint32_t)l%" PRIu32 ";\n", + 0, base, offset, value); + } + } + break; + } + + case WasmOpcode_memory_size: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "p%" PRIu32 ";\n", mem_idx); + } + break; + } + case WasmOpcode_memory_grow: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t pages = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", l%" PRIu32 ");\n", + mem_idx, mem_idx, pages); + } + break; + } + + case WasmOpcode_i32_const: { + uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value); + } + break; + } + case WasmOpcode_i64_const: { + uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value); + } + break; + } + case WasmOpcode_f32_const: { + uint32_t value = InputStream_readLittle_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value); + } + break; + } + case WasmOpcode_f64_const: { + uint64_t value = InputStream_readLittle_u64(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value); + } + break; + } + + case WasmOpcode_i32_eqz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "!l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_lt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " < (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_lt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_gt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " > (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_gt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_le_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " <= (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_le_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ge_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " >= (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ge_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_i64_eqz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "!l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_lt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " < (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_lt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_gt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " > (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_gt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_le_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " <= (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_le_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ge_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " >= (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ge_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_f32_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_lt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_gt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_le: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_ge: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_f64_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_lt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_gt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_le: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_ge: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_i32_clz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clz(l%" PRIu32 ") : 32;\n", + lhs, lhs); + } + break; + case WasmOpcode_i32_ctz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctz(l%" PRIu32 ") : 32;\n", + lhs, lhs); + } + break; + case WasmOpcode_i32_popcnt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "__builtin_popcount(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i32_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_div_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " / (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_div_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rem_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " %% (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rem_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_and: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_or: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_xor: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shr_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shr_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rotl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F) | " + "l%" PRIu32 " >> (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs); + } + break; + case WasmOpcode_i32_rotr: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F) | " + "l%" PRIu32 " << (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs); + } + break; + + case WasmOpcode_i64_clz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clzll(l%" PRIu32 ") : 64;\n", + lhs, lhs); + } + break; + case WasmOpcode_i64_ctz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctzll(l%" PRIu32 ") : 64;\n", + lhs, lhs); + } + break; + case WasmOpcode_i64_popcnt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "__builtin_popcountll(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i64_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_div_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " / (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_div_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rem_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " %% (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rem_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_and: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_or: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_xor: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shr_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shr_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rotl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F) | " + "l%" PRIu32 " >> (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs); + } + break; + case WasmOpcode_i64_rotr: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F) | " + "l%" PRIu32 " << (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs); + } + break; + + case WasmOpcode_f32_abs: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fabsf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_neg: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "-l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_ceil: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "ceilf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_floor: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "floorf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_trunc: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "truncf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_nearest: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "roundf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_sqrt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "sqrtf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_div: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_min: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fminf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f32_max: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fmaxf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f32_copysign: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "copysignf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + + case WasmOpcode_f64_abs: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fabs(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_neg: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "-l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_ceil: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "ceil(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_floor: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "floor(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_trunc: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "trunc(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_nearest: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "round(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_sqrt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "sqrt(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_div: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_min: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fmin(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f64_max: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fmax(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f64_copysign: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "copysign(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + + case WasmOpcode_i32_wrap_i64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_demote_f64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(float)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_promote_f32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(double)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_reinterpret_f32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i64_reinterpret_f64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_reinterpret_i32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_reinterpret_i64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs); + } + break; + + case WasmOpcode_i32_extend8_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_extend16_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend8_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend16_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + + case WasmOpcode_prefixed: + switch (InputStream_readLeb128_u32(&in)) { + case WasmPrefixedOpcode_i32_trunc_sat_f32_s: + case WasmPrefixedOpcode_i32_trunc_sat_f32_u: + case WasmPrefixedOpcode_i32_trunc_sat_f64_s: + case WasmPrefixedOpcode_i32_trunc_sat_f64_u: + case WasmPrefixedOpcode_i64_trunc_sat_f32_s: + case WasmPrefixedOpcode_i64_trunc_sat_f32_u: + case WasmPrefixedOpcode_i64_trunc_sat_f64_s: + case WasmPrefixedOpcode_i64_trunc_sat_f64_u: + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_memory_init: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readByte(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_data_drop: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_memory_copy: { + uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in); + uint32_t src_mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t n = FuncGen_stackPop(&fg); + uint32_t src = FuncGen_stackPop(&fg); + uint32_t dst = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "memcpy(&m%" PRIu32 "[l%" PRIu32 "], " + "&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n", + dst_mem_idx, dst, src_mem_idx, src, n); + } + break; + } + + case WasmPrefixedOpcode_memory_fill: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t n = FuncGen_stackPop(&fg); + uint32_t c = FuncGen_stackPop(&fg); + uint32_t s = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], " + "l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n); + } + break; + } + + case WasmPrefixedOpcode_table_init: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_elem_drop: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_copy: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_grow: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_size: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_fill: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + } + break; + } + } + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_used[param_i]) continue; + FuncGen_indent(&fg, out); + fprintf(out, "(void)l%" PRIu32 ";\n", param_i); + } + switch (func_type->result->len) { + case 0: break; + case 1: + FuncGen_indent(&fg, out); + fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + break; + default: panic("multiple function returns not supported"); + } + fputs("}\n\n", out); + } + } + + (void)InputStream_skipToSection(&in, WasmSectionId_data); + { + uint32_t len = InputStream_readLeb128_u32(&in); + fputs("static void init_data(void) {\n", out); + for (uint32_t i = 0; i < mems_len; i += 1) + fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n" + " m%" PRIu32 " = calloc(p%" PRIu32 ", UINT32_C(1) << 16);\n", + i, mems[i].limits.min, i, i); + for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { + uint32_t mem_idx; + switch (InputStream_readLeb128_u32(&in)) { + case 0: + mem_idx = 0; + break; + + case 2: + mem_idx = InputStream_readLeb128_u32(&in); + break; + + default: panic("unsupported data kind"); + } + uint32_t offset = evalExpr(&in); + uint32_t segment_len = InputStream_readLeb128_u32(&in); + fputc('\n', out); + fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {", + segment_i, segment_len); + for (uint32_t i = 0; i < segment_len; i += 1) { + if (i % 32 == 0) fputs("\n ", out); + fprintf(out, " 0x%02hhX,", InputStream_readByte(&in)); + } + fprintf(out, "\n" + " };\n" + " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n", + mem_idx, offset, segment_i, segment_len); + } + fputs("}\n", out); + } + + InputStream_close(&in); + fclose(out); +} diff --git a/stage1/zig1.c b/stage1/zig1.c deleted file mode 100644 index bc65179992b4..000000000000 --- a/stage1/zig1.c +++ /dev/null @@ -1,4567 +0,0 @@ -// TODO get rid of _GNU_SOURCE -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#endif - -#include - -#if defined(__APPLE__) -#define ZIG_TRIPLE_OS "macos" -#elif defined(_WIN32) -#define ZIG_TRIPLE_OS "windows" -#elif defined(__linux__) -#define ZIG_TRIPLE_OS "linux" -#elif defined(__FreeBSD__) -#define ZIG_TRIPLE_OS "freebsd" -#elif defined(__NetBSD__) -#define ZIG_TRIPLE_OS "netbsd" -#elif defined(__DragonFly__) -#define ZIG_TRIPLE_OS "dragonfly" -#elif defined(__OpenBSD__) -#define ZIG_TRIPLE_OS "openbsd" -#elif defined(__HAIKU__) -#define ZIG_TRIPLE_OS "haiku" -#elif defined(__sun) -#define ZIG_TRIPLE_OS "solaris" -#else -#error please add more os definitions above this line -#endif - -#if defined(__x86_64__) -#define ZIG_TRIPLE_ARCH "x86_64" -#elif defined(__aarch64__) -#define ZIG_TRIPLE_ARCH "aarch64" -#elif defined(__ARM_EABI__) -#define ZIG_TRIPLE_ARCH "arm" -#else -#error please add more arch definitions above this line -#endif - -enum wasi_errno_t { - WASI_ESUCCESS = 0, - WASI_E2BIG = 1, - WASI_EACCES = 2, - WASI_EADDRINUSE = 3, - WASI_EADDRNOTAVAIL = 4, - WASI_EAFNOSUPPORT = 5, - WASI_EAGAIN = 6, - WASI_EALREADY = 7, - WASI_EBADF = 8, - WASI_EBADMSG = 9, - WASI_EBUSY = 10, - WASI_ECANCELED = 11, - WASI_ECHILD = 12, - WASI_ECONNABORTED = 13, - WASI_ECONNREFUSED = 14, - WASI_ECONNRESET = 15, - WASI_EDEADLK = 16, - WASI_EDESTADDRREQ = 17, - WASI_EDOM = 18, - WASI_EDQUOT = 19, - WASI_EEXIST = 20, - WASI_EFAULT = 21, - WASI_EFBIG = 22, - WASI_EHOSTUNREACH = 23, - WASI_EIDRM = 24, - WASI_EILSEQ = 25, - WASI_EINPROGRESS = 26, - WASI_EINTR = 27, - WASI_EINVAL = 28, - WASI_EIO = 29, - WASI_EISCONN = 30, - WASI_EISDIR = 31, - WASI_ELOOP = 32, - WASI_EMFILE = 33, - WASI_EMLINK = 34, - WASI_EMSGSIZE = 35, - WASI_EMULTIHOP = 36, - WASI_ENAMETOOLONG = 37, - WASI_ENETDOWN = 38, - WASI_ENETRESET = 39, - WASI_ENETUNREACH = 40, - WASI_ENFILE = 41, - WASI_ENOBUFS = 42, - WASI_ENODEV = 43, - WASI_ENOENT = 44, - WASI_ENOEXEC = 45, - WASI_ENOLCK = 46, - WASI_ENOLINK = 47, - WASI_ENOMEM = 48, - WASI_ENOMSG = 49, - WASI_ENOPROTOOPT = 50, - WASI_ENOSPC = 51, - WASI_ENOSYS = 52, - WASI_ENOTCONN = 53, - WASI_ENOTDIR = 54, - WASI_ENOTEMPTY = 55, - WASI_ENOTRECOVERABLE = 56, - WASI_ENOTSOCK = 57, - WASI_EOPNOTSUPP = 58, - WASI_ENOTTY = 59, - WASI_ENXIO = 60, - WASI_EOVERFLOW = 61, - WASI_EOWNERDEAD = 62, - WASI_EPERM = 63, - WASI_EPIPE = 64, - WASI_EPROTO = 65, - WASI_EPROTONOSUPPORT = 66, - WASI_EPROTOTYPE = 67, - WASI_ERANGE = 68, - WASI_EROFS = 69, - WASI_ESPIPE = 70, - WASI_ESRCH = 71, - WASI_ESTALE = 72, - WASI_ETIMEDOUT = 73, - WASI_ETXTBSY = 74, - WASI_EXDEV = 75, - WASI_ENOTCAPABLE = 76, -}; - -static void panic(const char *msg) { - fprintf(stderr, "%s\n", msg); - abort(); -} - -static uint32_t min_u32(uint32_t a, uint32_t b) { - return (a < b) ? a : b; -} - -static uint32_t rotl32(uint32_t n, unsigned c) { - const unsigned mask = CHAR_BIT * sizeof(n) - 1; - c &= mask & 31; - return (n << c) | (n >> ((-c) & mask)); -} - -static uint32_t rotr32(uint32_t n, unsigned c) { - const unsigned mask = CHAR_BIT * sizeof(n) - 1; - c &= mask & 31; - return (n >> c) | (n << ((-c) & mask)); -} - -static uint64_t rotl64(uint64_t n, unsigned c) { - const unsigned mask = CHAR_BIT * sizeof(n) - 1; - c &= mask & 63; - return (n << c) | (n >> ((-c) & mask)); -} - -static uint64_t rotr64(uint64_t n, unsigned c) { - const unsigned mask = CHAR_BIT * sizeof(n) - 1; - c &= mask & 63; - return (n >> c) | (n << ((-c) & mask)); -} - -static void *arena_alloc(size_t n) { - void *ptr = malloc(n); - if (!ptr) panic("out of memory"); -#ifndef NDEBUG - memset(ptr, 0xaa, n); // to match the zig version -#endif - return ptr; -} - -static int err_wrap(const char *prefix, int rc) { - if (rc == -1) { - perror(prefix); - abort(); - } - return rc; -} - -static bool bs_isSet(const uint32_t *bitset, uint32_t index) { - return (bitset[index >> 5] >> (index & 0x1f)) & 1; -} -static void bs_set(uint32_t *bitset, uint32_t index) { - bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f)); -} -static void bs_unset(uint32_t *bitset, uint32_t index) { - bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f)); -} -static void bs_setValue(uint32_t *bitset, uint32_t index, bool value) { - if (value) bs_set(bitset, index); else bs_unset(bitset, index); -} - -struct ByteSlice { - char *ptr; - size_t len; -}; - -static struct ByteSlice read_file_alloc(const char *file_path) { - FILE *f = fopen(file_path, "rb"); - if (!f) { - fprintf(stderr, "failed to read %s: ", file_path); - perror(""); - abort(); - } - if (fseek(f, 0L, SEEK_END) == -1) panic("failed to seek"); - struct ByteSlice res; - res.len = ftell(f); - res.ptr = malloc(res.len); - rewind(f); - size_t amt_read = fread(res.ptr, 1, res.len, f); - if (amt_read != res.len) panic("short read"); - fclose(f); - return res; -} - - -struct Preopen { - int wasi_fd; - int host_fd; - const char *name; - size_t name_len; -}; - -static struct Preopen preopens_buffer[10]; -static size_t preopens_len = 0; - -static void add_preopen(int wasi_fd, const char *name, int host_fd) { - preopens_buffer[preopens_len].wasi_fd = wasi_fd; - preopens_buffer[preopens_len].host_fd = host_fd; - preopens_buffer[preopens_len].name = name; - preopens_buffer[preopens_len].name_len = strlen(name); - preopens_len += 1; -} - -static const struct Preopen *find_preopen(int32_t wasi_fd) { - for (size_t i = 0; i < preopens_len; i += 1) { - const struct Preopen *preopen = &preopens_buffer[i]; - if (preopen->wasi_fd == wasi_fd) { - return preopen; - } - } - return NULL; -} - -static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB - -static uint16_t read_u16_le(const char *ptr) { - const uint8_t *u8_ptr = (const uint8_t *)ptr; - return - (((uint64_t)u8_ptr[0]) << 0x00) | - (((uint64_t)u8_ptr[1]) << 0x08); -} - -static uint32_t read_u32_le(const char *ptr) { - const uint8_t *u8_ptr = (const uint8_t *)ptr; - return - (((uint64_t)u8_ptr[0]) << 0x00) | - (((uint64_t)u8_ptr[1]) << 0x08) | - (((uint64_t)u8_ptr[2]) << 0x10) | - (((uint64_t)u8_ptr[3]) << 0x18); -} - -static uint64_t read_u64_le(const char *ptr) { - const uint8_t *u8_ptr = (const uint8_t *)ptr; - return - (((uint64_t)u8_ptr[0]) << 0x00) | - (((uint64_t)u8_ptr[1]) << 0x08) | - (((uint64_t)u8_ptr[2]) << 0x10) | - (((uint64_t)u8_ptr[3]) << 0x18) | - (((uint64_t)u8_ptr[4]) << 0x20) | - (((uint64_t)u8_ptr[5]) << 0x28) | - (((uint64_t)u8_ptr[6]) << 0x30) | - (((uint64_t)u8_ptr[7]) << 0x38); -} - -static void write_u16_le(char *ptr, uint16_t x) { - uint8_t *u8_ptr = (uint8_t*)ptr; - u8_ptr[0] = (x >> 0x00); - u8_ptr[1] = (x >> 0x08); -} - -static void write_u32_le(char *ptr, uint32_t x) { - uint8_t *u8_ptr = (uint8_t*)ptr; - u8_ptr[0] = (x >> 0x00); - u8_ptr[1] = (x >> 0x08); - u8_ptr[2] = (x >> 0x10); - u8_ptr[3] = (x >> 0x18); -} - -static void write_u64_le(char *ptr, uint64_t x) { - uint8_t *u8_ptr = (uint8_t*)ptr; - u8_ptr[0] = (x >> 0x00); - u8_ptr[1] = (x >> 0x08); - u8_ptr[2] = (x >> 0x10); - u8_ptr[3] = (x >> 0x18); - u8_ptr[4] = (x >> 0x20); - u8_ptr[5] = (x >> 0x28); - u8_ptr[6] = (x >> 0x30); - u8_ptr[7] = (x >> 0x38); -} - -static uint32_t read32_uleb128(const char *ptr, uint32_t *i) { - uint32_t result = 0; - uint32_t shift = 0; - - for (;;) { - uint32_t byte = ptr[*i]; - *i += 1; - result |= ((byte & 0x7f) << shift); - shift += 7; - if ((byte & 0x80) == 0) return result; - if (shift >= 32) panic("read32_uleb128 failed"); - } -} - -static int64_t read64_ileb128(const char *ptr, uint32_t *i) { - int64_t result = 0; - uint32_t shift = 0; - - for (;;) { - uint64_t byte = ptr[*i]; - *i += 1; - result |= ((byte & 0x7f) << shift); - shift += 7; - if ((byte & 0x80) == 0) { - if ((byte & 0x40) && (shift < 64)) { - uint64_t extend = 0; - result |= (~extend << shift); - } - return result; - } - if (shift >= 64) panic("read64_ileb128 failed"); - } -} - -static int32_t read32_ileb128(const char *ptr, uint32_t *i) { - return read64_ileb128(ptr, i); -} - -static struct ByteSlice read_name(char *ptr, uint32_t *i) { - uint32_t len = read32_uleb128(ptr, i); - struct ByteSlice res; - res.ptr = ptr + *i; - res.len = len; - *i += len; - return res; -} - -enum Section { - Section_custom, - Section_type, - Section_import, - Section_function, - Section_table, - Section_memory, - Section_global, - Section_export, - Section_start, - Section_element, - Section_code, - Section_data, - Section_data_count, -}; - -enum Op { - Op_unreachable, - Op_br_void, - Op_br_32, - Op_br_64, - Op_br_nez_void, - Op_br_nez_32, - Op_br_nez_64, - Op_br_eqz_void, - Op_br_eqz_32, - Op_br_eqz_64, - Op_br_table_void, - Op_br_table_32, - Op_br_table_64, - Op_return_void, - Op_return_32, - Op_return_64, - Op_call_import, - Op_call_func, - Op_call_indirect, - Op_drop_32, - Op_drop_64, - Op_select_32, - Op_select_64, - Op_local_get_32, - Op_local_get_64, - Op_local_set_32, - Op_local_set_64, - Op_local_tee_32, - Op_local_tee_64, - Op_global_get_0_32, - Op_global_get_32, - Op_global_set_0_32, - Op_global_set_32, - Op_load_0_8, - Op_load_8, - Op_load_0_16, - Op_load_16, - Op_load_0_32, - Op_load_32, - Op_load_0_64, - Op_load_64, - Op_store_0_8, - Op_store_8, - Op_store_0_16, - Op_store_16, - Op_store_0_32, - Op_store_32, - Op_store_0_64, - Op_store_64, - Op_mem_size, - Op_mem_grow, - Op_const_0_32, - Op_const_0_64, - Op_const_1_32, - Op_const_1_64, - Op_const_32, - Op_const_64, - Op_const_umax_32, - Op_const_umax_64, - Op_eqz_32, - Op_eq_32, - Op_ne_32, - Op_slt_32, - Op_ult_32, - Op_sgt_32, - Op_ugt_32, - Op_sle_32, - Op_ule_32, - Op_sge_32, - Op_uge_32, - Op_eqz_64, - Op_eq_64, - Op_ne_64, - Op_slt_64, - Op_ult_64, - Op_sgt_64, - Op_ugt_64, - Op_sle_64, - Op_ule_64, - Op_sge_64, - Op_uge_64, - Op_feq_32, - Op_fne_32, - Op_flt_32, - Op_fgt_32, - Op_fle_32, - Op_fge_32, - Op_feq_64, - Op_fne_64, - Op_flt_64, - Op_fgt_64, - Op_fle_64, - Op_fge_64, - Op_clz_32, - Op_ctz_32, - Op_popcnt_32, - Op_add_32, - Op_sub_32, - Op_mul_32, - Op_sdiv_32, - Op_udiv_32, - Op_srem_32, - Op_urem_32, - Op_and_32, - Op_or_32, - Op_xor_32, - Op_shl_32, - Op_ashr_32, - Op_lshr_32, - Op_rol_32, - Op_ror_32, - Op_clz_64, - Op_ctz_64, - Op_popcnt_64, - Op_add_64, - Op_sub_64, - Op_mul_64, - Op_sdiv_64, - Op_udiv_64, - Op_srem_64, - Op_urem_64, - Op_and_64, - Op_or_64, - Op_xor_64, - Op_shl_64, - Op_ashr_64, - Op_lshr_64, - Op_rol_64, - Op_ror_64, - Op_fabs_32, - Op_fneg_32, - Op_ceil_32, - Op_floor_32, - Op_trunc_32, - Op_nearest_32, - Op_sqrt_32, - Op_fadd_32, - Op_fsub_32, - Op_fmul_32, - Op_fdiv_32, - Op_fmin_32, - Op_fmax_32, - Op_copysign_32, - Op_fabs_64, - Op_fneg_64, - Op_ceil_64, - Op_floor_64, - Op_trunc_64, - Op_nearest_64, - Op_sqrt_64, - Op_fadd_64, - Op_fsub_64, - Op_fmul_64, - Op_fdiv_64, - Op_fmin_64, - Op_fmax_64, - Op_copysign_64, - Op_ftos_32_32, - Op_ftou_32_32, - Op_ftos_32_64, - Op_ftou_32_64, - Op_sext_64_32, - Op_ftos_64_32, - Op_ftou_64_32, - Op_ftos_64_64, - Op_ftou_64_64, - Op_stof_32_32, - Op_utof_32_32, - Op_stof_32_64, - Op_utof_32_64, - Op_ftof_32_64, - Op_stof_64_32, - Op_utof_64_32, - Op_stof_64_64, - Op_utof_64_64, - Op_ftof_64_32, - Op_sext8_32, - Op_sext16_32, - Op_sext8_64, - Op_sext16_64, - Op_sext32_64, - Op_memcpy, - Op_memset, - - Op_wrap_32_64 = Op_drop_32, - Op_zext_64_32 = Op_const_0_32, - Op_last = Op_memset, -}; - -enum WasmOp { - WasmOp_unreachable = 0x00, - WasmOp_nop = 0x01, - WasmOp_block = 0x02, - WasmOp_loop = 0x03, - WasmOp_if = 0x04, - WasmOp_else = 0x05, - WasmOp_end = 0x0B, - WasmOp_br = 0x0C, - WasmOp_br_if = 0x0D, - WasmOp_br_table = 0x0E, - WasmOp_return = 0x0F, - WasmOp_call = 0x10, - WasmOp_call_indirect = 0x11, - WasmOp_drop = 0x1A, - WasmOp_select = 0x1B, - WasmOp_local_get = 0x20, - WasmOp_local_set = 0x21, - WasmOp_local_tee = 0x22, - WasmOp_global_get = 0x23, - WasmOp_global_set = 0x24, - WasmOp_i32_load = 0x28, - WasmOp_i64_load = 0x29, - WasmOp_f32_load = 0x2A, - WasmOp_f64_load = 0x2B, - WasmOp_i32_load8_s = 0x2C, - WasmOp_i32_load8_u = 0x2D, - WasmOp_i32_load16_s = 0x2E, - WasmOp_i32_load16_u = 0x2F, - WasmOp_i64_load8_s = 0x30, - WasmOp_i64_load8_u = 0x31, - WasmOp_i64_load16_s = 0x32, - WasmOp_i64_load16_u = 0x33, - WasmOp_i64_load32_s = 0x34, - WasmOp_i64_load32_u = 0x35, - WasmOp_i32_store = 0x36, - WasmOp_i64_store = 0x37, - WasmOp_f32_store = 0x38, - WasmOp_f64_store = 0x39, - WasmOp_i32_store8 = 0x3A, - WasmOp_i32_store16 = 0x3B, - WasmOp_i64_store8 = 0x3C, - WasmOp_i64_store16 = 0x3D, - WasmOp_i64_store32 = 0x3E, - WasmOp_memory_size = 0x3F, - WasmOp_memory_grow = 0x40, - WasmOp_i32_const = 0x41, - WasmOp_i64_const = 0x42, - WasmOp_f32_const = 0x43, - WasmOp_f64_const = 0x44, - WasmOp_i32_eqz = 0x45, - WasmOp_i32_eq = 0x46, - WasmOp_i32_ne = 0x47, - WasmOp_i32_lt_s = 0x48, - WasmOp_i32_lt_u = 0x49, - WasmOp_i32_gt_s = 0x4A, - WasmOp_i32_gt_u = 0x4B, - WasmOp_i32_le_s = 0x4C, - WasmOp_i32_le_u = 0x4D, - WasmOp_i32_ge_s = 0x4E, - WasmOp_i32_ge_u = 0x4F, - WasmOp_i64_eqz = 0x50, - WasmOp_i64_eq = 0x51, - WasmOp_i64_ne = 0x52, - WasmOp_i64_lt_s = 0x53, - WasmOp_i64_lt_u = 0x54, - WasmOp_i64_gt_s = 0x55, - WasmOp_i64_gt_u = 0x56, - WasmOp_i64_le_s = 0x57, - WasmOp_i64_le_u = 0x58, - WasmOp_i64_ge_s = 0x59, - WasmOp_i64_ge_u = 0x5A, - WasmOp_f32_eq = 0x5B, - WasmOp_f32_ne = 0x5C, - WasmOp_f32_lt = 0x5D, - WasmOp_f32_gt = 0x5E, - WasmOp_f32_le = 0x5F, - WasmOp_f32_ge = 0x60, - WasmOp_f64_eq = 0x61, - WasmOp_f64_ne = 0x62, - WasmOp_f64_lt = 0x63, - WasmOp_f64_gt = 0x64, - WasmOp_f64_le = 0x65, - WasmOp_f64_ge = 0x66, - WasmOp_i32_clz = 0x67, - WasmOp_i32_ctz = 0x68, - WasmOp_i32_popcnt = 0x69, - WasmOp_i32_add = 0x6A, - WasmOp_i32_sub = 0x6B, - WasmOp_i32_mul = 0x6C, - WasmOp_i32_div_s = 0x6D, - WasmOp_i32_div_u = 0x6E, - WasmOp_i32_rem_s = 0x6F, - WasmOp_i32_rem_u = 0x70, - WasmOp_i32_and = 0x71, - WasmOp_i32_or = 0x72, - WasmOp_i32_xor = 0x73, - WasmOp_i32_shl = 0x74, - WasmOp_i32_shr_s = 0x75, - WasmOp_i32_shr_u = 0x76, - WasmOp_i32_rotl = 0x77, - WasmOp_i32_rotr = 0x78, - WasmOp_i64_clz = 0x79, - WasmOp_i64_ctz = 0x7A, - WasmOp_i64_popcnt = 0x7B, - WasmOp_i64_add = 0x7C, - WasmOp_i64_sub = 0x7D, - WasmOp_i64_mul = 0x7E, - WasmOp_i64_div_s = 0x7F, - WasmOp_i64_div_u = 0x80, - WasmOp_i64_rem_s = 0x81, - WasmOp_i64_rem_u = 0x82, - WasmOp_i64_and = 0x83, - WasmOp_i64_or = 0x84, - WasmOp_i64_xor = 0x85, - WasmOp_i64_shl = 0x86, - WasmOp_i64_shr_s = 0x87, - WasmOp_i64_shr_u = 0x88, - WasmOp_i64_rotl = 0x89, - WasmOp_i64_rotr = 0x8A, - WasmOp_f32_abs = 0x8B, - WasmOp_f32_neg = 0x8C, - WasmOp_f32_ceil = 0x8D, - WasmOp_f32_floor = 0x8E, - WasmOp_f32_trunc = 0x8F, - WasmOp_f32_nearest = 0x90, - WasmOp_f32_sqrt = 0x91, - WasmOp_f32_add = 0x92, - WasmOp_f32_sub = 0x93, - WasmOp_f32_mul = 0x94, - WasmOp_f32_div = 0x95, - WasmOp_f32_min = 0x96, - WasmOp_f32_max = 0x97, - WasmOp_f32_copysign = 0x98, - WasmOp_f64_abs = 0x99, - WasmOp_f64_neg = 0x9A, - WasmOp_f64_ceil = 0x9B, - WasmOp_f64_floor = 0x9C, - WasmOp_f64_trunc = 0x9D, - WasmOp_f64_nearest = 0x9E, - WasmOp_f64_sqrt = 0x9F, - WasmOp_f64_add = 0xA0, - WasmOp_f64_sub = 0xA1, - WasmOp_f64_mul = 0xA2, - WasmOp_f64_div = 0xA3, - WasmOp_f64_min = 0xA4, - WasmOp_f64_max = 0xA5, - WasmOp_f64_copysign = 0xA6, - WasmOp_i32_wrap_i64 = 0xA7, - WasmOp_i32_trunc_f32_s = 0xA8, - WasmOp_i32_trunc_f32_u = 0xA9, - WasmOp_i32_trunc_f64_s = 0xAA, - WasmOp_i32_trunc_f64_u = 0xAB, - WasmOp_i64_extend_i32_s = 0xAC, - WasmOp_i64_extend_i32_u = 0xAD, - WasmOp_i64_trunc_f32_s = 0xAE, - WasmOp_i64_trunc_f32_u = 0xAF, - WasmOp_i64_trunc_f64_s = 0xB0, - WasmOp_i64_trunc_f64_u = 0xB1, - WasmOp_f32_convert_i32_s = 0xB2, - WasmOp_f32_convert_i32_u = 0xB3, - WasmOp_f32_convert_i64_s = 0xB4, - WasmOp_f32_convert_i64_u = 0xB5, - WasmOp_f32_demote_f64 = 0xB6, - WasmOp_f64_convert_i32_s = 0xB7, - WasmOp_f64_convert_i32_u = 0xB8, - WasmOp_f64_convert_i64_s = 0xB9, - WasmOp_f64_convert_i64_u = 0xBA, - WasmOp_f64_promote_f32 = 0xBB, - WasmOp_i32_reinterpret_f32 = 0xBC, - WasmOp_i64_reinterpret_f64 = 0xBD, - WasmOp_f32_reinterpret_i32 = 0xBE, - WasmOp_f64_reinterpret_i64 = 0xBF, - WasmOp_i32_extend8_s = 0xC0, - WasmOp_i32_extend16_s = 0xC1, - WasmOp_i64_extend8_s = 0xC2, - WasmOp_i64_extend16_s = 0xC3, - WasmOp_i64_extend32_s = 0xC4, - - WasmOp_prefixed = 0xFC, -}; - -enum WasmPrefixedOp { - WasmPrefixedOp_i32_trunc_sat_f32_s = 0x00, - WasmPrefixedOp_i32_trunc_sat_f32_u = 0x01, - WasmPrefixedOp_i32_trunc_sat_f64_s = 0x02, - WasmPrefixedOp_i32_trunc_sat_f64_u = 0x03, - WasmPrefixedOp_i64_trunc_sat_f32_s = 0x04, - WasmPrefixedOp_i64_trunc_sat_f32_u = 0x05, - WasmPrefixedOp_i64_trunc_sat_f64_s = 0x06, - WasmPrefixedOp_i64_trunc_sat_f64_u = 0x07, - WasmPrefixedOp_memory_init = 0x08, - WasmPrefixedOp_data_drop = 0x09, - WasmPrefixedOp_memory_copy = 0x0A, - WasmPrefixedOp_memory_fill = 0x0B, - WasmPrefixedOp_table_init = 0x0C, - WasmPrefixedOp_elem_drop = 0x0D, - WasmPrefixedOp_table_copy = 0x0E, - WasmPrefixedOp_table_grow = 0x0F, - WasmPrefixedOp_table_size = 0x10, - WasmPrefixedOp_table_fill = 0x11, -}; - -static const uint32_t wasm_page_size = 64 * 1024; - -struct ProgramCounter { - uint32_t opcode; - uint32_t operand; -}; - -struct TypeInfo { - uint32_t param_count; - // bitset with param_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit - uint32_t param_types; - uint32_t result_count; - // bitset with result_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit - uint32_t result_types; -}; - -struct Function { - uint32_t id; - // Index to start of code in opcodes/operands. - struct ProgramCounter entry_pc; - uint32_t type_idx; - uint32_t locals_size; -}; - -enum ImpMod { - ImpMod_wasi_snapshot_preview1, -}; - -enum ImpName { - ImpName_args_get, - ImpName_args_sizes_get, - ImpName_clock_time_get, - ImpName_debug, - ImpName_debug_slice, - ImpName_environ_get, - ImpName_environ_sizes_get, - ImpName_fd_close, - ImpName_fd_fdstat_get, - ImpName_fd_filestat_get, - ImpName_fd_filestat_set_size, - ImpName_fd_filestat_set_times, - ImpName_fd_pread, - ImpName_fd_prestat_dir_name, - ImpName_fd_prestat_get, - ImpName_fd_pwrite, - ImpName_fd_read, - ImpName_fd_readdir, - ImpName_fd_write, - ImpName_path_create_directory, - ImpName_path_filestat_get, - ImpName_path_open, - ImpName_path_remove_directory, - ImpName_path_rename, - ImpName_path_unlink_file, - ImpName_proc_exit, - ImpName_random_get, -}; - -struct Import { - enum ImpMod mod; - enum ImpName name; - uint32_t type_idx; -}; - -struct VirtualMachine { - uint32_t *stack; - /// Points to one after the last stack item. - uint32_t stack_top; - struct ProgramCounter pc; - /// Actual memory usage of the WASI code. The capacity is max_memory. - uint32_t memory_len; - const char *mod_ptr; - uint8_t *opcodes; - uint32_t *operands; - struct Function *functions; - /// Type index to start of type in module_bytes. - struct TypeInfo *types; - uint64_t *globals; - char *memory; - struct Import *imports; - uint32_t imports_len; - const char **args; - uint32_t *table; -}; - -static int to_host_fd(int32_t wasi_fd) { - const struct Preopen *preopen = find_preopen(wasi_fd); - if (!preopen) return wasi_fd; - return preopen->host_fd; -} - -static enum wasi_errno_t to_wasi_err(int err) { - switch (err) { - case E2BIG: return WASI_E2BIG; - case EACCES: return WASI_EACCES; - case EADDRINUSE: return WASI_EADDRINUSE; - case EADDRNOTAVAIL: return WASI_EADDRNOTAVAIL; - case EAFNOSUPPORT: return WASI_EAFNOSUPPORT; - case EAGAIN: return WASI_EAGAIN; - case EALREADY: return WASI_EALREADY; - case EBADF: return WASI_EBADF; - case EBADMSG: return WASI_EBADMSG; - case EBUSY: return WASI_EBUSY; - case ECANCELED: return WASI_ECANCELED; - case ECHILD: return WASI_ECHILD; - case ECONNABORTED: return WASI_ECONNABORTED; - case ECONNREFUSED: return WASI_ECONNREFUSED; - case ECONNRESET: return WASI_ECONNRESET; - case EDEADLK: return WASI_EDEADLK; - case EDESTADDRREQ: return WASI_EDESTADDRREQ; - case EDOM: return WASI_EDOM; - case EDQUOT: return WASI_EDQUOT; - case EEXIST: return WASI_EEXIST; - case EFAULT: return WASI_EFAULT; - case EFBIG: return WASI_EFBIG; - case EHOSTUNREACH: return WASI_EHOSTUNREACH; - case EIDRM: return WASI_EIDRM; - case EILSEQ: return WASI_EILSEQ; - case EINPROGRESS: return WASI_EINPROGRESS; - case EINTR: return WASI_EINTR; - case EINVAL: return WASI_EINVAL; - case EIO: return WASI_EIO; - case EISCONN: return WASI_EISCONN; - case EISDIR: return WASI_EISDIR; - case ELOOP: return WASI_ELOOP; - case EMFILE: return WASI_EMFILE; - case EMLINK: return WASI_EMLINK; - case EMSGSIZE: return WASI_EMSGSIZE; - case EMULTIHOP: return WASI_EMULTIHOP; - case ENAMETOOLONG: return WASI_ENAMETOOLONG; - case ENETDOWN: return WASI_ENETDOWN; - case ENETRESET: return WASI_ENETRESET; - case ENETUNREACH: return WASI_ENETUNREACH; - case ENFILE: return WASI_ENFILE; - case ENOBUFS: return WASI_ENOBUFS; - case ENODEV: return WASI_ENODEV; - case ENOENT: return WASI_ENOENT; - case ENOEXEC: return WASI_ENOEXEC; - case ENOLCK: return WASI_ENOLCK; - case ENOLINK: return WASI_ENOLINK; - case ENOMEM: return WASI_ENOMEM; - case ENOMSG: return WASI_ENOMSG; - case ENOPROTOOPT: return WASI_ENOPROTOOPT; - case ENOSPC: return WASI_ENOSPC; - case ENOSYS: return WASI_ENOSYS; - case ENOTCONN: return WASI_ENOTCONN; - case ENOTDIR: return WASI_ENOTDIR; - case ENOTEMPTY: return WASI_ENOTEMPTY; - case ENOTRECOVERABLE: return WASI_ENOTRECOVERABLE; - case ENOTSOCK: return WASI_ENOTSOCK; - case EOPNOTSUPP: return WASI_EOPNOTSUPP; - case ENOTTY: return WASI_ENOTTY; - case ENXIO: return WASI_ENXIO; - case EOVERFLOW: return WASI_EOVERFLOW; - case EOWNERDEAD: return WASI_EOWNERDEAD; - case EPERM: return WASI_EPERM; - case EPIPE: return WASI_EPIPE; - case EPROTO: return WASI_EPROTO; - case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT; - case EPROTOTYPE: return WASI_EPROTOTYPE; - case ERANGE: return WASI_ERANGE; - case EROFS: return WASI_EROFS; - case ESPIPE: return WASI_ESPIPE; - case ESRCH: return WASI_ESRCH; - case ESTALE: return WASI_ESTALE; - case ETIMEDOUT: return WASI_ETIMEDOUT; - case ETXTBSY: return WASI_ETXTBSY; - case EXDEV: return WASI_EXDEV; - default: - fprintf(stderr, "unexpected errno: %s\n", strerror(err)); - abort(); - }; -} - -enum wasi_filetype_t { - wasi_filetype_t_UNKNOWN, - wasi_filetype_t_BLOCK_DEVICE, - wasi_filetype_t_CHARACTER_DEVICE, - wasi_filetype_t_DIRECTORY, - wasi_filetype_t_REGULAR_FILE, - wasi_filetype_t_SOCKET_DGRAM, - wasi_filetype_t_SOCKET_STREAM, - wasi_filetype_t_SYMBOLIC_LINK, -}; - -static const uint16_t WASI_O_CREAT = 0x0001; -static const uint16_t WASI_O_DIRECTORY = 0x0002; -static const uint16_t WASI_O_EXCL = 0x0004; -static const uint16_t WASI_O_TRUNC = 0x0008; - -static const uint16_t WASI_FDFLAG_APPEND = 0x0001; -static const uint16_t WASI_FDFLAG_DSYNC = 0x0002; -static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004; -static const uint16_t WASI_FDFLAG_SYNC = 0x0010; - -static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull; -static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull; - -static enum wasi_filetype_t to_wasi_filetype(mode_t st_mode) { - switch (st_mode & S_IFMT) { - case S_IFBLK: - return wasi_filetype_t_BLOCK_DEVICE; - case S_IFCHR: - return wasi_filetype_t_CHARACTER_DEVICE; - case S_IFDIR: - return wasi_filetype_t_DIRECTORY; - case S_IFLNK: - return wasi_filetype_t_SYMBOLIC_LINK; - case S_IFREG: - return wasi_filetype_t_REGULAR_FILE; - default: - return wasi_filetype_t_UNKNOWN; - } -} - -static uint64_t to_wasi_timestamp(struct timespec ts) { - return ts.tv_sec * 1000000000ull + ts.tv_nsec; -} - -/// const filestat_t = extern struct { -/// dev: device_t, u64 -/// ino: inode_t, u64 -/// filetype: filetype_t, u8 -/// nlink: linkcount_t, u64 -/// size: filesize_t, u64 -/// atim: timestamp_t, u64 -/// mtim: timestamp_t, u64 -/// ctim: timestamp_t, u64 -/// }; -static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm, - uint32_t buf, struct stat st) -{ - write_u64_le(vm->memory + buf + 0x00, 0); // device - write_u64_le(vm->memory + buf + 0x08, st.st_ino); - write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode)); - write_u64_le(vm->memory + buf + 0x18, 1); // nlink - write_u64_le(vm->memory + buf + 0x20, st.st_size); -#if defined(__APPLE__) - write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atimespec)); - write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtimespec)); - write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctimespec)); -#else - write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim)); - write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim)); - write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim)); -#endif - return WASI_ESUCCESS; -} - -/// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; -static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, - uint32_t argc, uint32_t argv_buf_size) -{ - uint32_t args_len = 0; - size_t buf_size = 0; - while (vm->args[args_len]) { - buf_size += strlen(vm->args[args_len]) + 1; - args_len += 1; - } - write_u32_le(vm->memory + argc, args_len); - write_u32_le(vm->memory + argv_buf_size, buf_size); - return WASI_ESUCCESS; -} - -/// extern fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; -static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, - uint32_t argv, uint32_t argv_buf) -{ - uint32_t argv_buf_i = 0; - uint32_t arg_i = 0; - for (;; arg_i += 1) { - const char *arg = vm->args[arg_i]; - if (!arg) break; - // Write the arg to the buffer. - uint32_t argv_ptr = argv_buf + argv_buf_i; - uint32_t arg_len = strlen(arg) + 1; - memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len); - argv_buf_i += arg_len; - - write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr); - } - return WASI_ESUCCESS; -} - -/// extern fn random_get(buf: [*]u8, buf_len: usize) errno_t; -static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, - uint32_t buf, uint32_t buf_len) -{ -#ifdef __linux__ - if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) { - panic("getrandom failed"); - } -#else - for (uint32_t i = 0; i < buf_len; i += 1) { - vm->memory[buf + i] = rand(); - } -#endif - return WASI_ESUCCESS; -} - -/// fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t; -/// const prestat_t = extern struct { -/// pr_type: u8, -/// u: usize, -/// }; -static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, - int32_t fd, uint32_t buf) -{ - const struct Preopen *preopen = find_preopen(fd); - if (!preopen) return WASI_EBADF; - write_u32_le(vm->memory + buf + 0, 0); - write_u32_le(vm->memory + buf + 4, preopen->name_len); - return WASI_ESUCCESS; -} - -/// fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t; -static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm, - int32_t fd, uint32_t path, uint32_t path_len) -{ - const struct Preopen *preopen = find_preopen(fd); - if (!preopen) return WASI_EBADF; - if (path_len != preopen->name_len) - panic("wasi_fd_prestat_dir_name expects correct name_len"); - memcpy(vm->memory + path, preopen->name, path_len); - return WASI_ESUCCESS; -} - -/// extern fn fd_close(fd: fd_t) errno_t; -static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) { - int host_fd = to_host_fd(fd); - close(host_fd); - return WASI_ESUCCESS; -} - -static enum wasi_errno_t wasi_fd_read( - struct VirtualMachine *vm, - int32_t fd, - uint32_t iovs, // [*]const iovec_t - uint32_t iovs_len, // usize - uint32_t nread // *usize -) { - int host_fd = to_host_fd(fd); - uint32_t i = 0; - size_t total_read = 0; - for (; i < iovs_len; i += 1) { - uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); - uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); - ssize_t amt_read = read(host_fd, vm->memory + ptr, len); - if (amt_read < 0) return to_wasi_err(errno); - total_read += amt_read; - if (amt_read != len) break; - } - write_u32_le(vm->memory + nread, total_read); - return WASI_ESUCCESS; -} - -/// extern fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t; -/// const ciovec_t = extern struct { -/// base: [*]const u8, -/// len: usize, -/// }; -static enum wasi_errno_t wasi_fd_write(struct VirtualMachine *vm, - int32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t nwritten) -{ - int host_fd = to_host_fd(fd); - size_t total_written = 0; - for (uint32_t i = 0; i < iovs_len; i += 1) { - uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); - uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); - ssize_t written = write(host_fd, vm->memory + ptr, len); - if (written < 0) return to_wasi_err(errno); - total_written += written; - if (written != len) break; - } - write_u32_le(vm->memory + nwritten, total_written); - return WASI_ESUCCESS; -} - -static enum wasi_errno_t wasi_fd_pwrite( - struct VirtualMachine *vm, - int32_t fd, - uint32_t iovs, // [*]const ciovec_t - uint32_t iovs_len, // usize - uint64_t offset, // wasi.filesize_t, - uint32_t written_ptr // *usize -) { - int host_fd = to_host_fd(fd); - uint32_t i = 0; - size_t written = 0; - for (; i < iovs_len; i += 1) { - uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); - uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); - ssize_t w = pwrite(host_fd, vm->memory + ptr, len, offset + written); - if (w < 0) return to_wasi_err(errno); - written += w; - if (w != len) break; - } - write_u32_le(vm->memory + written_ptr, written); - return WASI_ESUCCESS; -} - -///extern fn path_open( -/// dirfd: fd_t, -/// dirflags: lookupflags_t, -/// path: [*]const u8, -/// path_len: usize, -/// oflags: oflags_t, -/// fs_rights_base: rights_t, -/// fs_rights_inheriting: rights_t, -/// fs_flags: fdflags_t, -/// fd: *fd_t, -///) errno_t; -static enum wasi_errno_t wasi_path_open( - struct VirtualMachine *vm, - int32_t dirfd, - uint32_t dirflags, // wasi.lookupflags_t, - uint32_t path, - uint32_t path_len, - uint16_t oflags, // wasi.oflags_t, - uint64_t fs_rights_base, // wasi.rights_t, - uint64_t fs_rights_inheriting, // wasi.rights_t, - uint16_t fs_flags, // wasi.fdflags_t, - uint32_t fd -) { - char sub_path[PATH_MAX]; - memcpy(sub_path, vm->memory + path, path_len); - sub_path[path_len] = 0; - - int host_fd = to_host_fd(dirfd); - uint32_t flags = - (((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) | - (((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) | - (((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) | - (((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) | - (((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) | - (((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) | - (((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) | - (((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0); - - if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) && - ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0)) - { - flags |= O_RDWR; - } else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) { - flags |= O_WRONLY; - } else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) { - flags |= O_RDONLY; // no-op because O_RDONLY is 0 - } - mode_t mode = 0644; - int res_fd = openat(host_fd, sub_path, flags, mode); - if (res_fd == -1) return to_wasi_err(errno); - write_u32_le(vm->memory + fd, res_fd); - return WASI_ESUCCESS; -} - -static enum wasi_errno_t wasi_path_filestat_get( - struct VirtualMachine *vm, - int32_t fd, - uint32_t flags, // wasi.lookupflags_t, - uint32_t path, // [*]const u8 - uint32_t path_len, // usize - uint32_t buf // *filestat_t -) { - char sub_path[PATH_MAX]; - memcpy(sub_path, vm->memory + path, path_len); - sub_path[path_len] = 0; - - int host_fd = to_host_fd(fd); - struct stat st; - if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno); - return finish_wasi_stat(vm, buf, st); -} - -/// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; -static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, - int32_t wasi_fd, uint32_t path, uint32_t path_len) -{ - char sub_path[PATH_MAX]; - memcpy(sub_path, vm->memory + path, path_len); - sub_path[path_len] = 0; - - int host_fd = to_host_fd(wasi_fd); - if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno); - return WASI_ESUCCESS; -} - -static enum wasi_errno_t wasi_path_rename( - struct VirtualMachine *vm, - int32_t old_fd, - uint32_t old_path_ptr, // [*]const u8 - uint32_t old_path_len, // usize - int32_t new_fd, - uint32_t new_path_ptr, // [*]const u8 - uint32_t new_path_len // usize -) { - char old_path[PATH_MAX]; - memcpy(old_path, vm->memory + old_path_ptr, old_path_len); - old_path[old_path_len] = 0; - - char new_path[PATH_MAX]; - memcpy(new_path, vm->memory + new_path_ptr, new_path_len); - new_path[new_path_len] = 0; - - int old_host_fd = to_host_fd(old_fd); - int new_host_fd = to_host_fd(new_fd); - if (renameat(old_host_fd, old_path, new_host_fd, new_path) == -1) return to_wasi_err(errno); - return WASI_ESUCCESS; -} - -/// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; -static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { - int host_fd = to_host_fd(fd); - struct stat st; - if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); - return finish_wasi_stat(vm, buf, st); -} - -static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, - int32_t fd, uint64_t size) -{ - int host_fd = to_host_fd(fd); - if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno); - return WASI_ESUCCESS; -} - -/// pub extern "wasi_snapshot_preview1" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t; -/// pub const fdstat_t = extern struct { -/// fs_filetype: filetype_t, u8 -/// fs_flags: fdflags_t, u16 -/// fs_rights_base: rights_t, u64 -/// fs_rights_inheriting: rights_t, u64 -/// }; -static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { - int host_fd = to_host_fd(fd); - struct stat st; - if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); - write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode)); - write_u16_le(vm->memory + buf + 0x02, 0); // flags - write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base - write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting - return WASI_ESUCCESS; -} - -/// extern fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; -static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, - uint32_t clock_id, uint64_t precision, uint32_t timestamp) -{ - if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC"); - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno); - uint64_t wasi_ts = to_wasi_timestamp(ts); - write_u64_le(vm->memory + timestamp, wasi_ts); - return WASI_ESUCCESS; -} - -///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; -void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { - fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64 " %" PRIx64 "\n", vm->memory + text, n, n); -} - -/// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; -void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { - fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr); -} - -enum StackType { - ST_32, - ST_64, -}; - -struct Label { - enum WasmOp opcode; - uint32_t stack_index; - uint32_t stack_offset; - struct TypeInfo type_info; - // this is a UINT32_MAX terminated linked list that is stored in the operands array - uint32_t ref_list; - union { - struct ProgramCounter loop_pc; - uint32_t else_ref; - } extra; -}; - -static uint32_t Label_operandCount(const struct Label *label) { - if (label->opcode == WasmOp_loop) { - return label->type_info.param_count; - } else { - return label->type_info.result_count; - } -} - -static enum StackType Label_operandType(const struct Label *label, uint32_t index) { - if (label->opcode == WasmOp_loop) { - return bs_isSet(&label->type_info.param_types, index); - } else { - return bs_isSet(&label->type_info.result_types, index); - } -} - -#define max_stack_depth (1 << 12) - -struct StackInfo { - uint32_t top_index; - uint32_t top_offset; - uint32_t types[max_stack_depth >> 5]; - uint32_t offsets[max_stack_depth]; -}; - -static enum StackType si_top(const struct StackInfo *si) { - return bs_isSet(si->types, si->top_index - 1); -} - -static enum StackType si_local(const struct StackInfo *si, uint32_t local_idx) { - return bs_isSet(si->types, local_idx); -} - -static void si_push(struct StackInfo *si, enum StackType entry_type) { - bs_setValue(si->types, si->top_index, entry_type); - si->offsets[si->top_index] = si->top_offset; - si->top_index += 1; - si->top_offset += 1 + entry_type; -} - -static void si_pop(struct StackInfo *si, enum StackType entry_type) { - assert(si_top(si) == entry_type); - si->top_index -= 1; - si->top_offset -= 1 + entry_type; - assert(si->top_offset == si->offsets[si->top_index]); -} - -static void vm_decodeCode(struct VirtualMachine *vm, struct TypeInfo *func_type_info, - uint32_t *code_i, struct ProgramCounter *pc, struct StackInfo *stack) -{ - const char *mod_ptr = vm->mod_ptr; - uint8_t *opcodes = vm->opcodes; - uint32_t *operands = vm->operands; - - // push return address - uint32_t frame_size = stack->top_offset; - si_push(stack, ST_32); - si_push(stack, ST_32); - - uint32_t unreachable_depth = 0; - uint32_t label_i = 0; - static struct Label labels[1 << 9]; -#ifndef NDEBUG - memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version -#endif - labels[label_i].opcode = WasmOp_block; - labels[label_i].stack_index = stack->top_index; - labels[label_i].stack_offset = stack->top_offset; - labels[label_i].type_info = *func_type_info; - labels[label_i].ref_list = UINT32_MAX; - - enum { - State_default, - State_bool_not, - } state = State_default; - - for (;;) { - assert(stack->top_index >= labels[0].stack_index); - assert(stack->top_offset >= labels[0].stack_offset); - enum WasmOp opcode = (uint8_t)mod_ptr[*code_i]; - *code_i += 1; - enum WasmPrefixedOp prefixed_opcode; - if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i); - - //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand); - //struct ProgramCounter old_pc = *pc; - - if (unreachable_depth == 0) - switch (opcode) { - case WasmOp_unreachable: - case WasmOp_nop: - case WasmOp_block: - case WasmOp_loop: - case WasmOp_else: - case WasmOp_end: - case WasmOp_br: - case WasmOp_return: - case WasmOp_call: - case WasmOp_local_get: - case WasmOp_local_set: - case WasmOp_local_tee: - case WasmOp_global_get: - case WasmOp_global_set: - case WasmOp_drop: - case WasmOp_select: - break; // handled manually below - - case WasmOp_if: - case WasmOp_br_if: - case WasmOp_br_table: - case WasmOp_call_indirect: - si_pop(stack, ST_32); - break; - - case WasmOp_memory_size: - case WasmOp_i32_const: - case WasmOp_f32_const: - si_push(stack, ST_32); - break; - - case WasmOp_i64_const: - case WasmOp_f64_const: - si_push(stack, ST_64); - break; - - case WasmOp_i32_load: - case WasmOp_f32_load: - case WasmOp_i32_load8_s: - case WasmOp_i32_load8_u: - case WasmOp_i32_load16_s: - case WasmOp_i32_load16_u: - si_pop(stack, ST_32); - si_push(stack, ST_32); - break; - - case WasmOp_i64_load: - case WasmOp_f64_load: - case WasmOp_i64_load8_s: - case WasmOp_i64_load8_u: - case WasmOp_i64_load16_s: - case WasmOp_i64_load16_u: - case WasmOp_i64_load32_s: - case WasmOp_i64_load32_u: - si_pop(stack, ST_32); - si_push(stack, ST_64); - break; - - case WasmOp_memory_grow: - case WasmOp_i32_eqz: - case WasmOp_i32_clz: - case WasmOp_i32_ctz: - case WasmOp_i32_popcnt: - case WasmOp_f32_abs: - case WasmOp_f32_neg: - case WasmOp_f32_ceil: - case WasmOp_f32_floor: - case WasmOp_f32_trunc: - case WasmOp_f32_nearest: - case WasmOp_f32_sqrt: - case WasmOp_i32_trunc_f32_s: - case WasmOp_i32_trunc_f32_u: - case WasmOp_f32_convert_i32_s: - case WasmOp_f32_convert_i32_u: - case WasmOp_i32_reinterpret_f32: - case WasmOp_f32_reinterpret_i32: - case WasmOp_i32_extend8_s: - case WasmOp_i32_extend16_s: - si_pop(stack, ST_32); - si_push(stack, ST_32); - break; - - case WasmOp_i64_eqz: - case WasmOp_i32_wrap_i64: - case WasmOp_i32_trunc_f64_s: - case WasmOp_i32_trunc_f64_u: - case WasmOp_f32_convert_i64_s: - case WasmOp_f32_convert_i64_u: - case WasmOp_f32_demote_f64: - si_pop(stack, ST_64); - si_push(stack, ST_32); - break; - - case WasmOp_i64_clz: - case WasmOp_i64_ctz: - case WasmOp_i64_popcnt: - case WasmOp_f64_abs: - case WasmOp_f64_neg: - case WasmOp_f64_ceil: - case WasmOp_f64_floor: - case WasmOp_f64_trunc: - case WasmOp_f64_nearest: - case WasmOp_f64_sqrt: - case WasmOp_i64_trunc_f64_s: - case WasmOp_i64_trunc_f64_u: - case WasmOp_f64_convert_i64_s: - case WasmOp_f64_convert_i64_u: - case WasmOp_i64_reinterpret_f64: - case WasmOp_f64_reinterpret_i64: - case WasmOp_i64_extend8_s: - case WasmOp_i64_extend16_s: - case WasmOp_i64_extend32_s: - si_pop(stack, ST_64); - si_push(stack, ST_64); - break; - - case WasmOp_i64_extend_i32_s: - case WasmOp_i64_extend_i32_u: - case WasmOp_i64_trunc_f32_s: - case WasmOp_i64_trunc_f32_u: - case WasmOp_f64_convert_i32_s: - case WasmOp_f64_convert_i32_u: - case WasmOp_f64_promote_f32: - si_pop(stack, ST_32); - si_push(stack, ST_64); - break; - - case WasmOp_i32_store: - case WasmOp_f32_store: - case WasmOp_i32_store8: - case WasmOp_i32_store16: - si_pop(stack, ST_32); - si_pop(stack, ST_32); - break; - - case WasmOp_i64_store: - case WasmOp_f64_store: - case WasmOp_i64_store8: - case WasmOp_i64_store16: - case WasmOp_i64_store32: - si_pop(stack, ST_64); - si_pop(stack, ST_32); - break; - - case WasmOp_i32_eq: - case WasmOp_i32_ne: - case WasmOp_i32_lt_s: - case WasmOp_i32_lt_u: - case WasmOp_i32_gt_s: - case WasmOp_i32_gt_u: - case WasmOp_i32_le_s: - case WasmOp_i32_le_u: - case WasmOp_i32_ge_s: - case WasmOp_i32_ge_u: - case WasmOp_f32_eq: - case WasmOp_f32_ne: - case WasmOp_f32_lt: - case WasmOp_f32_gt: - case WasmOp_f32_le: - case WasmOp_f32_ge: - si_pop(stack, ST_32); - si_pop(stack, ST_32); - si_push(stack, ST_32); - break; - - case WasmOp_i64_eq: - case WasmOp_i64_ne: - case WasmOp_i64_lt_s: - case WasmOp_i64_lt_u: - case WasmOp_i64_gt_s: - case WasmOp_i64_gt_u: - case WasmOp_i64_le_s: - case WasmOp_i64_le_u: - case WasmOp_i64_ge_s: - case WasmOp_i64_ge_u: - case WasmOp_f64_eq: - case WasmOp_f64_ne: - case WasmOp_f64_lt: - case WasmOp_f64_gt: - case WasmOp_f64_le: - case WasmOp_f64_ge: - si_pop(stack, ST_64); - si_pop(stack, ST_64); - si_push(stack, ST_32); - break; - - case WasmOp_i32_add: - case WasmOp_i32_sub: - case WasmOp_i32_mul: - case WasmOp_i32_div_s: - case WasmOp_i32_div_u: - case WasmOp_i32_rem_s: - case WasmOp_i32_rem_u: - case WasmOp_i32_and: - case WasmOp_i32_or: - case WasmOp_i32_xor: - case WasmOp_i32_shl: - case WasmOp_i32_shr_s: - case WasmOp_i32_shr_u: - case WasmOp_i32_rotl: - case WasmOp_i32_rotr: - case WasmOp_f32_add: - case WasmOp_f32_sub: - case WasmOp_f32_mul: - case WasmOp_f32_div: - case WasmOp_f32_min: - case WasmOp_f32_max: - case WasmOp_f32_copysign: - si_pop(stack, ST_32); - si_pop(stack, ST_32); - si_push(stack, ST_32); - break; - - case WasmOp_i64_add: - case WasmOp_i64_sub: - case WasmOp_i64_mul: - case WasmOp_i64_div_s: - case WasmOp_i64_div_u: - case WasmOp_i64_rem_s: - case WasmOp_i64_rem_u: - case WasmOp_i64_and: - case WasmOp_i64_or: - case WasmOp_i64_xor: - case WasmOp_i64_shl: - case WasmOp_i64_shr_s: - case WasmOp_i64_shr_u: - case WasmOp_i64_rotl: - case WasmOp_i64_rotr: - case WasmOp_f64_add: - case WasmOp_f64_sub: - case WasmOp_f64_mul: - case WasmOp_f64_div: - case WasmOp_f64_min: - case WasmOp_f64_max: - case WasmOp_f64_copysign: - si_pop(stack, ST_64); - si_pop(stack, ST_64); - si_push(stack, ST_64); - break; - - case WasmOp_prefixed: - switch (prefixed_opcode) { - case WasmPrefixedOp_i32_trunc_sat_f32_s: - case WasmPrefixedOp_i32_trunc_sat_f32_u: - si_pop(stack, ST_32); - si_push(stack, ST_32); - break; - - case WasmPrefixedOp_i32_trunc_sat_f64_s: - case WasmPrefixedOp_i32_trunc_sat_f64_u: - si_pop(stack, ST_64); - si_push(stack, ST_32); - break; - - case WasmPrefixedOp_i64_trunc_sat_f32_s: - case WasmPrefixedOp_i64_trunc_sat_f32_u: - si_pop(stack, ST_32); - si_push(stack, ST_64); - break; - - case WasmPrefixedOp_i64_trunc_sat_f64_s: - case WasmPrefixedOp_i64_trunc_sat_f64_u: - si_pop(stack, ST_64); - si_push(stack, ST_64); - break; - - case WasmPrefixedOp_memory_init: - case WasmPrefixedOp_memory_copy: - case WasmPrefixedOp_memory_fill: - case WasmPrefixedOp_table_init: - case WasmPrefixedOp_table_copy: - si_pop(stack, ST_32); - si_pop(stack, ST_32); - si_pop(stack, ST_32); - break; - - case WasmPrefixedOp_table_fill: - si_pop(stack, ST_32); - panic("si_pop(stack, unreachable);"); - si_pop(stack, ST_32); - break; - - case WasmPrefixedOp_data_drop: - case WasmPrefixedOp_elem_drop: - break; - - case WasmPrefixedOp_table_grow: - si_pop(stack, ST_32); - panic("si_pop(stack, unreachable);"); - si_push(stack, ST_32); - break; - - case WasmPrefixedOp_table_size: - si_push(stack, ST_32); - break; - - default: panic("unexpected prefixed opcode"); - } - break; - - default: panic("unexpected opcode"); - } - switch (opcode) { - case WasmOp_unreachable: - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_unreachable; - pc->opcode += 1; - unreachable_depth += 1; - } - break; - - case WasmOp_nop: - case WasmOp_i32_reinterpret_f32: - case WasmOp_i64_reinterpret_f64: - case WasmOp_f32_reinterpret_i32: - case WasmOp_f64_reinterpret_i64: - break; - - case WasmOp_block: - case WasmOp_loop: - case WasmOp_if: - { - int64_t block_type = read64_ileb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - label_i += 1; - struct Label *label = &labels[label_i]; - label->opcode = opcode; - if (block_type < 0) { - label->type_info.param_count = 0; - label->type_info.param_types = 0; - label->type_info.result_count = block_type != -0x40; - switch (block_type) { - case -0x40: - case -1: - case -3: - label->type_info.result_types = 0; - break; - case -2: - case -4: - label->type_info.result_types = UINT32_MAX; - break; - default: panic("unexpected param type"); - } - } else label->type_info = vm->types[block_type]; - - uint32_t param_i = label->type_info.param_count; - while (param_i > 0) { - param_i -= 1; - si_pop(stack, bs_isSet(&label->type_info.param_types, param_i)); - } - label->stack_index = stack->top_index; - label->stack_offset = stack->top_offset; - label->ref_list = UINT32_MAX; - for (; param_i < label->type_info.param_count; param_i += 1) - si_push(stack, bs_isSet(&label->type_info.param_types, param_i)); - - switch (opcode) { - case WasmOp_block: - break; - - case WasmOp_loop: - label->extra.loop_pc = *pc; - break; - - case WasmOp_if: - if (state == State_bool_not) { - pc->opcode -= 1; - opcodes[pc->opcode] = Op_br_nez_void; - } else opcodes[pc->opcode] = Op_br_eqz_void; - pc->opcode += 1; - operands[pc->operand] = 0; - label->extra.else_ref = pc->operand + 1; - pc->operand += 3; - break; - - default: panic("unexpected label opcode"); - } - } else unreachable_depth += 1; - } - break; - - case WasmOp_else: - if (unreachable_depth <= 1) { - struct Label *label = &labels[label_i]; - assert(label->opcode == WasmOp_if); - label->opcode = WasmOp_else; - - if (unreachable_depth == 0) { - uint32_t operand_count = Label_operandCount(label); - for (uint32_t operand_i = operand_count; operand_i > 0; ) { - operand_i -= 1; - si_pop(stack, Label_operandType(label, operand_i)); - } - assert(stack->top_index == label->stack_index); - assert(stack->top_offset == label->stack_offset); - - switch (operand_count) { - case 0: - opcodes[pc->opcode] = Op_br_void; - break; - - case 1: - //fprintf(stderr, "label_i=%u operand_type=%d\n", - // label_i, Label_operandType(label, 0)); - switch (Label_operandType(label, 0)) { - case ST_32: opcodes[pc->opcode] = Op_br_32; break; - case ST_64: opcodes[pc->opcode] = Op_br_64; break; - } - break; - - default: panic("unexpected operand count"); - } - pc->opcode += 1; - operands[pc->operand + 0] = stack->top_offset - label->stack_offset; - operands[pc->operand + 1] = label->ref_list; - label->ref_list = pc->operand + 1; - pc->operand += 3; - } else unreachable_depth = 0; - - operands[label->extra.else_ref + 0] = pc->opcode; - operands[label->extra.else_ref + 1] = pc->operand; - for (uint32_t param_i = 0; param_i < label->type_info.param_count; param_i += 1) - si_push(stack, bs_isSet(&label->type_info.param_types, param_i)); - } - break; - - case WasmOp_end: - if (unreachable_depth <= 1) { - struct Label *label = &labels[label_i]; - struct ProgramCounter *target_pc = (label->opcode == WasmOp_loop) ? &label->extra.loop_pc : pc; - if (label->opcode == WasmOp_if) { - operands[label->extra.else_ref + 0] = target_pc->opcode; - operands[label->extra.else_ref + 1] = target_pc->operand; - } - uint32_t ref = label->ref_list; - while (ref != UINT32_MAX) { - uint32_t next_ref = operands[ref]; - operands[ref + 0] = target_pc->opcode; - operands[ref + 1] = target_pc->operand; - ref = next_ref; - } - - if (unreachable_depth == 0) { - for (uint32_t result_i = label->type_info.result_count; result_i > 0; ) { - result_i -= 1; - si_pop(stack, bs_isSet(&label->type_info.result_types, result_i)); - } - } else unreachable_depth = 0; - - if (label_i == 0) { - assert(stack->top_index == label->stack_index); - assert(stack->top_offset == label->stack_offset); - - switch (labels[0].type_info.result_count) { - case 0: - opcodes[pc->opcode] = Op_return_void; - break; - - case 1: - switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) { - case ST_32: opcodes[pc->opcode] = Op_return_32; break; - case ST_64: opcodes[pc->opcode] = Op_return_64; break; - } - break; - - default: panic("unexpected operand count"); - } - pc->opcode += 1; - operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset; - operands[pc->operand + 1] = frame_size; - pc->operand += 2; - return; - } - label_i -= 1; - - stack->top_index = label->stack_index; - stack->top_offset = label->stack_offset; - for (uint32_t result_i = 0; result_i < label->type_info.result_count; result_i += 1) - si_push(stack, bs_isSet(&label->type_info.result_types, result_i)); - } else unreachable_depth -= 1; - break; - - case WasmOp_br: - case WasmOp_br_if: - { - uint32_t label_idx = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - struct Label *label = &labels[label_i - label_idx]; - uint32_t operand_count = Label_operandCount(label); - uint32_t operand_i = operand_count; - while (operand_i > 0) { - operand_i -= 1; - si_pop(stack, Label_operandType(label, operand_i)); - } - - switch (opcode) { - case WasmOp_br: - switch (operand_count) { - case 0: - opcodes[pc->opcode] = Op_br_void; - break; - - case 1: - switch (Label_operandType(label, 0)) { - case ST_32: opcodes[pc->opcode] = Op_br_32; break; - case ST_64: opcodes[pc->opcode] = Op_br_64; break; - } - break; - - default: panic("unexpected operand count"); - } - break; - - case WasmOp_br_if: - switch (operand_count) { - case 0: - if (state == State_bool_not) { - pc->opcode -= 1; - opcodes[pc->opcode] = Op_br_eqz_void; - } else opcodes[pc->opcode] = Op_br_nez_void; - break; - - case 1: - switch (Label_operandType(label, 0)) { - case ST_32: - if (state == State_bool_not) { - pc->opcode -= 1; - opcodes[pc->opcode] = Op_br_eqz_32; - } else opcodes[pc->opcode] = Op_br_nez_32; - break; - - case ST_64: - if (state == State_bool_not) { - pc->opcode -= 1; - opcodes[pc->opcode] = Op_br_eqz_64; - } else opcodes[pc->opcode] = Op_br_nez_64; - break; - } - break; - - default: panic("unexpected operand count"); - } - break; - - default: panic("unexpected opcode"); - } - pc->opcode += 1; - operands[pc->operand + 0] = stack->top_offset - label->stack_offset; - operands[pc->operand + 1] = label->ref_list; - label->ref_list = pc->operand + 1; - pc->operand += 3; - - switch (opcode) { - case WasmOp_br: - unreachable_depth += 1; - break; - - case WasmOp_br_if: - for (; operand_i < operand_count; operand_i += 1) - si_push(stack, Label_operandType(label, operand_i)); - break; - - default: panic("unexpected opcode"); - } - } - } - break; - - case WasmOp_br_table: - { - uint32_t labels_len = read32_uleb128(mod_ptr, code_i); - for (uint32_t i = 0; i <= labels_len; i += 1) { - uint32_t label_idx = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth != 0) continue; - struct Label *label = &labels[label_i - label_idx]; - if (i == 0) { - uint32_t operand_count = Label_operandCount(label); - for (uint32_t operand_i = operand_count; operand_i > 0; ) { - operand_i -= 1; - si_pop(stack, Label_operandType(label, operand_i)); - } - - switch (operand_count) { - case 0: - opcodes[pc->opcode] = Op_br_table_void; - break; - - case 1: - switch (Label_operandType(label, 0)) { - case ST_32: opcodes[pc->opcode] = Op_br_table_32; break; - case ST_64: opcodes[pc->opcode] = Op_br_table_64; break; - } - break; - - default: panic("unexpected operand count"); - } - pc->opcode += 1; - operands[pc->operand] = labels_len; - pc->operand += 1; - } - operands[pc->operand + 0] = stack->top_offset - label->stack_offset; - operands[pc->operand + 1] = label->ref_list; - label->ref_list = pc->operand + 1; - pc->operand += 3; - } - if (unreachable_depth == 0) unreachable_depth += 1; - } - break; - - case WasmOp_return: - if (unreachable_depth == 0) { - for (uint32_t result_i = labels[0].type_info.result_count; result_i > 0; ) { - result_i -= 1; - si_pop(stack, bs_isSet(&labels[0].type_info.result_types, result_i)); - } - - switch (labels[0].type_info.result_count) { - case 0: - opcodes[pc->opcode] = Op_return_void; - break; - - case 1: - switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) { - case ST_32: opcodes[pc->opcode] = Op_return_32; break; - case ST_64: opcodes[pc->opcode] = Op_return_64; break; - } - break; - - default: panic("unexpected operand count"); - } - pc->opcode += 1; - operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset; - operands[pc->operand + 1] = frame_size; - pc->operand += 2; - unreachable_depth += 1; - } - break; - - case WasmOp_call: - { - uint32_t fn_id = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - uint32_t type_idx; - if (fn_id < vm->imports_len) { - opcodes[pc->opcode + 0] = Op_call_import; - opcodes[pc->opcode + 1] = fn_id; - pc->opcode += 2; - type_idx = vm->imports[fn_id].type_idx; - } else { - uint32_t fn_idx = fn_id - vm->imports_len; - opcodes[pc->opcode] = Op_call_func; - pc->opcode += 1; - operands[pc->operand] = fn_idx; - pc->operand += 1; - type_idx = vm->functions[fn_idx].type_idx; - } - struct TypeInfo *type_info = &vm->types[type_idx]; - - for (uint32_t param_i = type_info->param_count; param_i > 0; ) { - param_i -= 1; - si_pop(stack, bs_isSet(&type_info->param_types, param_i)); - } - for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) - si_push(stack, bs_isSet(&type_info->result_types, result_i)); - } - } - break; - - case WasmOp_call_indirect: - { - uint32_t type_idx = read32_uleb128(mod_ptr, code_i); - if (read32_uleb128(mod_ptr, code_i) != 0) panic("unexpected table index"); - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_call_indirect; - pc->opcode += 1; - - struct TypeInfo *type_info = &vm->types[type_idx]; - for (uint32_t param_i = type_info->param_count; param_i > 0; ) { - param_i -= 1; - si_pop(stack, bs_isSet(&type_info->param_types, param_i)); - } - for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1) - si_push(stack, bs_isSet(&type_info->result_types, result_i)); - } - } - break; - - case WasmOp_select: - case WasmOp_drop: - if (unreachable_depth == 0) { - if (opcode == WasmOp_select) si_pop(stack, ST_32); - enum StackType operand_type = si_top(stack); - si_pop(stack, operand_type); - if (opcode == WasmOp_select) { - si_pop(stack, operand_type); - si_push(stack, operand_type); - } - switch (opcode) { - case WasmOp_select: - switch (operand_type) { - case ST_32: opcodes[pc->opcode] = Op_select_32; break; - case ST_64: opcodes[pc->opcode] = Op_select_64; break; - } - break; - - case WasmOp_drop: - switch (operand_type) { - case ST_32: opcodes[pc->opcode] = Op_drop_32; break; - case ST_64: opcodes[pc->opcode] = Op_drop_64; break; - } - break; - - default: panic("unexpected opcode"); - } - pc->opcode += 1; - } - break; - - case WasmOp_local_get: - case WasmOp_local_set: - case WasmOp_local_tee: - { - uint32_t local_idx = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - enum StackType local_type = si_local(stack, local_idx); - switch (opcode) { - case WasmOp_local_get: - switch (local_type) { - case ST_32: opcodes[pc->opcode] = Op_local_get_32; break; - case ST_64: opcodes[pc->opcode] = Op_local_get_64; break; - } - break; - - case WasmOp_local_set: - switch (local_type) { - case ST_32: opcodes[pc->opcode] = Op_local_set_32; break; - case ST_64: opcodes[pc->opcode] = Op_local_set_64; break; - } - break; - - case WasmOp_local_tee: - switch (local_type) { - case ST_32: opcodes[pc->opcode] = Op_local_tee_32; break; - case ST_64: opcodes[pc->opcode] = Op_local_tee_64; break; - } - break; - - default: panic("unexpected opcode"); - } - pc->opcode += 1; - operands[pc->operand] = stack->top_offset - stack->offsets[local_idx]; - pc->operand += 1; - switch (opcode) { - case WasmOp_local_get: - si_push(stack, local_type); - break; - - case WasmOp_local_set: - si_pop(stack, local_type); - break; - - case WasmOp_local_tee: - si_pop(stack, local_type); - si_push(stack, local_type); - break; - - default: panic("unexpected opcode"); - } - } - } - break; - - case WasmOp_global_get: - case WasmOp_global_set: - { - uint32_t global_idx = read32_uleb128(mod_ptr, code_i); - if (unreachable_depth == 0) { - enum StackType global_type = ST_32; // all globals assumed to be 32-bit - switch (opcode) { - case WasmOp_global_get: - switch (global_idx) { - case 0: opcodes[pc->opcode] = Op_global_get_0_32; break; - default: opcodes[pc->opcode] = Op_global_get_32; break; - } - break; - - case WasmOp_global_set: - switch (global_idx) { - case 0: opcodes[pc->opcode] = Op_global_set_0_32; break; - default: opcodes[pc->opcode] = Op_global_set_32; break; - } - break; - - default: panic("unexpected opcode"); - } - pc->opcode += 1; - if (global_idx != 0) { - operands[pc->operand] = global_idx; - pc->operand += 1; - } - switch (opcode) { - case WasmOp_global_get: - si_push(stack, global_type); - break; - - case WasmOp_global_set: - si_pop(stack, global_type); - break; - - default: panic("unexpected opcode"); - } - } - } - break; - - case WasmOp_i32_load: - case WasmOp_i64_load: - case WasmOp_f32_load: - case WasmOp_f64_load: - case WasmOp_i32_load8_s: - case WasmOp_i32_load8_u: - case WasmOp_i32_load16_s: - case WasmOp_i32_load16_u: - case WasmOp_i64_load8_s: - case WasmOp_i64_load8_u: - case WasmOp_i64_load16_s: - case WasmOp_i64_load16_u: - case WasmOp_i64_load32_s: - case WasmOp_i64_load32_u: - case WasmOp_i32_store: - case WasmOp_i64_store: - case WasmOp_f32_store: - case WasmOp_f64_store: - case WasmOp_i32_store8: - case WasmOp_i32_store16: - case WasmOp_i64_store8: - case WasmOp_i64_store16: - case WasmOp_i64_store32: - { - uint32_t alignment = read32_uleb128(mod_ptr, code_i); - uint32_t offset = read32_uleb128(mod_ptr, code_i); - (void)alignment; - if (unreachable_depth == 0) { - switch (opcode) { - default: break; - - case WasmOp_i64_store8: case WasmOp_i64_store16: case WasmOp_i64_store32: - opcodes[pc->opcode] = Op_drop_32; - pc->opcode += 1; - break; - } - switch (opcode) { - case WasmOp_i32_load8_s: case WasmOp_i32_load8_u: - case WasmOp_i64_load8_s: case WasmOp_i64_load8_u: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_load_0_8; break; - default: opcodes[pc->opcode] = Op_load_8; break; - } - break; - - case WasmOp_i32_load16_s: case WasmOp_i32_load16_u: - case WasmOp_i64_load16_s: case WasmOp_i64_load16_u: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_load_0_16; break; - default: opcodes[pc->opcode] = Op_load_16; break; - } - break; - - case WasmOp_i32_load: case WasmOp_f32_load: - case WasmOp_i64_load32_s: case WasmOp_i64_load32_u: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_load_0_32; break; - default: opcodes[pc->opcode] = Op_load_32; break; - } - break; - - case WasmOp_i64_load: case WasmOp_f64_load: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_load_0_64; break; - default: opcodes[pc->opcode] = Op_load_64; break; - } - break; - - case WasmOp_i32_store8: case WasmOp_i64_store8: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_store_0_8; break; - default: opcodes[pc->opcode] = Op_store_8; break; - } - break; - - case WasmOp_i32_store16: case WasmOp_i64_store16: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_store_0_16; break; - default: opcodes[pc->opcode] = Op_store_16; break; - } - break; - - case WasmOp_i32_store: case WasmOp_f32_store: case WasmOp_i64_store32: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_store_0_32; break; - default: opcodes[pc->opcode] = Op_store_32; break; - } - break; - - case WasmOp_i64_store: case WasmOp_f64_store: - switch (offset) { - case 0: opcodes[pc->opcode] = Op_store_0_64; break; - default: opcodes[pc->opcode] = Op_store_64; break; - } - break; - - default: panic("unexpected opcode"); - } - pc->opcode += 1; - switch (offset) { - case 0: break; - - default: - operands[pc->operand] = offset; - pc->operand += 1; - break; - } - switch (opcode) { - default: break; - - case WasmOp_i32_load8_s: case WasmOp_i64_load8_s: - opcodes[pc->opcode] = Op_sext8_32; - pc->opcode += 1; - break; - - case WasmOp_i32_load16_s: case WasmOp_i64_load16_s: - opcodes[pc->opcode] = Op_sext16_32; - pc->opcode += 1; - break; - } - switch (opcode) { - default: break; - - case WasmOp_i64_load8_s: case WasmOp_i64_load16_s: case WasmOp_i64_load32_s: - opcodes[pc->opcode] = Op_sext_64_32; - pc->opcode += 1; - break; - - case WasmOp_i64_load8_u: case WasmOp_i64_load16_u: case WasmOp_i64_load32_u: - opcodes[pc->opcode] = Op_zext_64_32; - pc->opcode += 1; - break; - } - } - } - break; - - case WasmOp_memory_size: - case WasmOp_memory_grow: - { - if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); - *code_i += 1; - if (unreachable_depth == 0) { - switch (opcode) { - case WasmOp_memory_size: opcodes[pc->opcode] = Op_mem_size; break; - case WasmOp_memory_grow: opcodes[pc->opcode] = Op_mem_grow; break; - default: panic("unexpected opcode"); - } - pc->opcode += 1; - } - } - break; - - case WasmOp_i32_const: - case WasmOp_f32_const: - { - uint32_t value; - switch (opcode) { - case WasmOp_i32_const: value = read32_ileb128(mod_ptr, code_i); break; - - case WasmOp_f32_const: - value = read_u32_le(&mod_ptr[*code_i]); - *code_i += sizeof(value); - break; - - default: panic("unexpected opcode"); - } - if (unreachable_depth == 0) { - switch (value) { - case 0: opcodes[pc->opcode] = Op_const_0_32; break; - case 1: opcodes[pc->opcode] = Op_const_1_32; break; - - default: - opcodes[pc->opcode] = Op_const_32; - operands[pc->operand] = value; - pc->operand += 1; - break; - - case UINT32_MAX: opcodes[pc->opcode] = Op_const_umax_32; break; - } - pc->opcode += 1; - } - } - break; - - case WasmOp_i64_const: - case WasmOp_f64_const: - { - uint64_t value; - switch (opcode) { - case WasmOp_i64_const: value = read64_ileb128(mod_ptr, code_i); break; - - case WasmOp_f64_const: - value = read_u64_le(&mod_ptr[*code_i]); - *code_i += sizeof(value); - break; - - default: panic("unexpected opcode"); - } - - if (unreachable_depth == 0) { - switch (value) { - case 0: opcodes[pc->opcode] = Op_const_0_64; break; - case 1: opcodes[pc->opcode] = Op_const_1_64; break; - - default: - opcodes[pc->opcode] = Op_const_64; - operands[pc->operand + 0] = (uint32_t)(value >> 0); - operands[pc->operand + 1] = (uint32_t)(value >> 32); - pc->operand += 2; - break; - - case UINT64_MAX: opcodes[pc->opcode] = Op_const_umax_64; break; - } - pc->opcode += 1; - } - } - break; - - default: - if (unreachable_depth == 0) { - switch (opcode) { - case WasmOp_i32_eqz: opcodes[pc->opcode] = Op_eqz_32; break; - case WasmOp_i32_eq: opcodes[pc->opcode] = Op_eq_32; break; - case WasmOp_i32_ne: opcodes[pc->opcode] = Op_ne_32; break; - case WasmOp_i32_lt_s: opcodes[pc->opcode] = Op_slt_32; break; - case WasmOp_i32_lt_u: opcodes[pc->opcode] = Op_ult_32; break; - case WasmOp_i32_gt_s: opcodes[pc->opcode] = Op_sgt_32; break; - case WasmOp_i32_gt_u: opcodes[pc->opcode] = Op_ugt_32; break; - case WasmOp_i32_le_s: opcodes[pc->opcode] = Op_sle_32; break; - case WasmOp_i32_le_u: opcodes[pc->opcode] = Op_ule_32; break; - case WasmOp_i32_ge_s: opcodes[pc->opcode] = Op_sge_32; break; - case WasmOp_i32_ge_u: opcodes[pc->opcode] = Op_uge_32; break; - case WasmOp_i64_eqz: opcodes[pc->opcode] = Op_eqz_64; break; - case WasmOp_i64_eq: opcodes[pc->opcode] = Op_eq_64; break; - case WasmOp_i64_ne: opcodes[pc->opcode] = Op_ne_64; break; - case WasmOp_i64_lt_s: opcodes[pc->opcode] = Op_slt_64; break; - case WasmOp_i64_lt_u: opcodes[pc->opcode] = Op_ult_64; break; - case WasmOp_i64_gt_s: opcodes[pc->opcode] = Op_sgt_64; break; - case WasmOp_i64_gt_u: opcodes[pc->opcode] = Op_ugt_64; break; - case WasmOp_i64_le_s: opcodes[pc->opcode] = Op_sle_64; break; - case WasmOp_i64_le_u: opcodes[pc->opcode] = Op_ule_64; break; - case WasmOp_i64_ge_s: opcodes[pc->opcode] = Op_sge_64; break; - case WasmOp_i64_ge_u: opcodes[pc->opcode] = Op_uge_64; break; - case WasmOp_f32_eq: opcodes[pc->opcode] = Op_feq_32; break; - case WasmOp_f32_ne: opcodes[pc->opcode] = Op_fne_32; break; - case WasmOp_f32_lt: opcodes[pc->opcode] = Op_flt_32; break; - case WasmOp_f32_gt: opcodes[pc->opcode] = Op_fgt_32; break; - case WasmOp_f32_le: opcodes[pc->opcode] = Op_fle_32; break; - case WasmOp_f32_ge: opcodes[pc->opcode] = Op_fge_32; break; - case WasmOp_f64_eq: opcodes[pc->opcode] = Op_feq_64; break; - case WasmOp_f64_ne: opcodes[pc->opcode] = Op_fne_64; break; - case WasmOp_f64_lt: opcodes[pc->opcode] = Op_flt_64; break; - case WasmOp_f64_gt: opcodes[pc->opcode] = Op_fgt_64; break; - case WasmOp_f64_le: opcodes[pc->opcode] = Op_fle_64; break; - case WasmOp_f64_ge: opcodes[pc->opcode] = Op_fge_64; break; - case WasmOp_i32_clz: opcodes[pc->opcode] = Op_clz_32; break; - case WasmOp_i32_ctz: opcodes[pc->opcode] = Op_ctz_32; break; - case WasmOp_i32_popcnt: opcodes[pc->opcode] = Op_popcnt_32; break; - case WasmOp_i32_add: opcodes[pc->opcode] = Op_add_32; break; - case WasmOp_i32_sub: opcodes[pc->opcode] = Op_sub_32; break; - case WasmOp_i32_mul: opcodes[pc->opcode] = Op_mul_32; break; - case WasmOp_i32_div_s: opcodes[pc->opcode] = Op_sdiv_32; break; - case WasmOp_i32_div_u: opcodes[pc->opcode] = Op_udiv_32; break; - case WasmOp_i32_rem_s: opcodes[pc->opcode] = Op_srem_32; break; - case WasmOp_i32_rem_u: opcodes[pc->opcode] = Op_urem_32; break; - case WasmOp_i32_and: opcodes[pc->opcode] = Op_and_32; break; - case WasmOp_i32_or: opcodes[pc->opcode] = Op_or_32; break; - case WasmOp_i32_xor: opcodes[pc->opcode] = Op_xor_32; break; - case WasmOp_i32_shl: opcodes[pc->opcode] = Op_shl_32; break; - case WasmOp_i32_shr_s: opcodes[pc->opcode] = Op_ashr_32; break; - case WasmOp_i32_shr_u: opcodes[pc->opcode] = Op_lshr_32; break; - case WasmOp_i32_rotl: opcodes[pc->opcode] = Op_rol_32; break; - case WasmOp_i32_rotr: opcodes[pc->opcode] = Op_ror_32; break; - case WasmOp_i64_clz: opcodes[pc->opcode] = Op_clz_64; break; - case WasmOp_i64_ctz: opcodes[pc->opcode] = Op_ctz_64; break; - case WasmOp_i64_popcnt: opcodes[pc->opcode] = Op_popcnt_64; break; - case WasmOp_i64_add: opcodes[pc->opcode] = Op_add_64; break; - case WasmOp_i64_sub: opcodes[pc->opcode] = Op_sub_64; break; - case WasmOp_i64_mul: opcodes[pc->opcode] = Op_mul_64; break; - case WasmOp_i64_div_s: opcodes[pc->opcode] = Op_sdiv_64; break; - case WasmOp_i64_div_u: opcodes[pc->opcode] = Op_udiv_64; break; - case WasmOp_i64_rem_s: opcodes[pc->opcode] = Op_srem_64; break; - case WasmOp_i64_rem_u: opcodes[pc->opcode] = Op_urem_64; break; - case WasmOp_i64_and: opcodes[pc->opcode] = Op_and_64; break; - case WasmOp_i64_or: opcodes[pc->opcode] = Op_or_64; break; - case WasmOp_i64_xor: opcodes[pc->opcode] = Op_xor_64; break; - case WasmOp_i64_shl: opcodes[pc->opcode] = Op_shl_64; break; - case WasmOp_i64_shr_s: opcodes[pc->opcode] = Op_ashr_64; break; - case WasmOp_i64_shr_u: opcodes[pc->opcode] = Op_lshr_64; break; - case WasmOp_i64_rotl: opcodes[pc->opcode] = Op_rol_64; break; - case WasmOp_i64_rotr: opcodes[pc->opcode] = Op_ror_64; break; - case WasmOp_f32_abs: opcodes[pc->opcode] = Op_fabs_32; break; - case WasmOp_f32_neg: opcodes[pc->opcode] = Op_fneg_32; break; - case WasmOp_f32_ceil: opcodes[pc->opcode] = Op_ceil_32; break; - case WasmOp_f32_floor: opcodes[pc->opcode] = Op_floor_32; break; - case WasmOp_f32_trunc: opcodes[pc->opcode] = Op_trunc_32; break; - case WasmOp_f32_nearest: opcodes[pc->opcode] = Op_nearest_32; break; - case WasmOp_f32_sqrt: opcodes[pc->opcode] = Op_sqrt_32; break; - case WasmOp_f32_add: opcodes[pc->opcode] = Op_fadd_32; break; - case WasmOp_f32_sub: opcodes[pc->opcode] = Op_fsub_32; break; - case WasmOp_f32_mul: opcodes[pc->opcode] = Op_fmul_32; break; - case WasmOp_f32_div: opcodes[pc->opcode] = Op_fdiv_32; break; - case WasmOp_f32_min: opcodes[pc->opcode] = Op_fmin_32; break; - case WasmOp_f32_max: opcodes[pc->opcode] = Op_fmax_32; break; - case WasmOp_f32_copysign: opcodes[pc->opcode] = Op_copysign_32; break; - case WasmOp_f64_abs: opcodes[pc->opcode] = Op_fabs_64; break; - case WasmOp_f64_neg: opcodes[pc->opcode] = Op_fneg_64; break; - case WasmOp_f64_ceil: opcodes[pc->opcode] = Op_ceil_64; break; - case WasmOp_f64_floor: opcodes[pc->opcode] = Op_floor_64; break; - case WasmOp_f64_trunc: opcodes[pc->opcode] = Op_trunc_64; break; - case WasmOp_f64_nearest: opcodes[pc->opcode] = Op_nearest_64; break; - case WasmOp_f64_sqrt: opcodes[pc->opcode] = Op_sqrt_64; break; - case WasmOp_f64_add: opcodes[pc->opcode] = Op_fadd_64; break; - case WasmOp_f64_sub: opcodes[pc->opcode] = Op_fsub_64; break; - case WasmOp_f64_mul: opcodes[pc->opcode] = Op_fmul_64; break; - case WasmOp_f64_div: opcodes[pc->opcode] = Op_fdiv_64; break; - case WasmOp_f64_min: opcodes[pc->opcode] = Op_fmin_64; break; - case WasmOp_f64_max: opcodes[pc->opcode] = Op_fmax_64; break; - case WasmOp_f64_copysign: opcodes[pc->opcode] = Op_copysign_64; break; - case WasmOp_i32_wrap_i64: opcodes[pc->opcode] = Op_wrap_32_64; break; - case WasmOp_i32_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_32_32; break; - case WasmOp_i32_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_32_32; break; - case WasmOp_i32_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_32_64; break; - case WasmOp_i32_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_32_64; break; - case WasmOp_i64_extend_i32_s: opcodes[pc->opcode] = Op_sext_64_32; break; - case WasmOp_i64_extend_i32_u: opcodes[pc->opcode] = Op_zext_64_32; break; - case WasmOp_i64_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_64_32; break; - case WasmOp_i64_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_64_32; break; - case WasmOp_i64_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_64_64; break; - case WasmOp_i64_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_64_64; break; - case WasmOp_f32_convert_i32_s: opcodes[pc->opcode] = Op_stof_32_32; break; - case WasmOp_f32_convert_i32_u: opcodes[pc->opcode] = Op_utof_32_32; break; - case WasmOp_f32_convert_i64_s: opcodes[pc->opcode] = Op_stof_32_64; break; - case WasmOp_f32_convert_i64_u: opcodes[pc->opcode] = Op_utof_32_64; break; - case WasmOp_f32_demote_f64: opcodes[pc->opcode] = Op_ftof_32_64; break; - case WasmOp_f64_convert_i32_s: opcodes[pc->opcode] = Op_stof_64_32; break; - case WasmOp_f64_convert_i32_u: opcodes[pc->opcode] = Op_utof_64_32; break; - case WasmOp_f64_convert_i64_s: opcodes[pc->opcode] = Op_stof_64_64; break; - case WasmOp_f64_convert_i64_u: opcodes[pc->opcode] = Op_utof_64_64; break; - case WasmOp_f64_promote_f32: opcodes[pc->opcode] = Op_ftof_64_32; break; - case WasmOp_i32_extend8_s: opcodes[pc->opcode] = Op_sext8_32; break; - case WasmOp_i32_extend16_s: opcodes[pc->opcode] = Op_sext16_32; break; - case WasmOp_i64_extend8_s: opcodes[pc->opcode] = Op_sext8_64; break; - case WasmOp_i64_extend16_s: opcodes[pc->opcode] = Op_sext16_64; break; - case WasmOp_i64_extend32_s: opcodes[pc->opcode] = Op_sext32_64; break; - default: panic("unexpected opcode"); - } - pc->opcode += 1; - } - break; - - case WasmOp_prefixed: - switch (prefixed_opcode) { - case WasmPrefixedOp_memory_copy: - if (mod_ptr[*code_i + 0] != 0 || mod_ptr[*code_i + 1] != 0) - panic("unexpected memory index"); - *code_i += 2; - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_memcpy; - pc->opcode += 1; - } - break; - - case WasmPrefixedOp_memory_fill: - if (mod_ptr[*code_i] != 0) panic("unexpected memory index"); - *code_i += 1; - if (unreachable_depth == 0) { - opcodes[pc->opcode] = Op_memset; - pc->opcode += 1; - } - break; - - default: panic("unexpected opcode"); - } - break; - } - switch (opcode) { - default: state = State_default; break; - case WasmOp_i32_eqz: state = State_bool_not; break; - } - - //for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) { - // fprintf(stderr, "decoded opcode[%u] = %u\n", i, opcodes[i]); - //} - //for (uint32_t i = old_pc.operand; i < pc->operand; i += 1) { - // fprintf(stderr, "decoded operand[%u] = %u\n", i, operands[i]); - //} - } -} - -static void vm_push_u32(struct VirtualMachine *vm, uint32_t value) { - vm->stack[vm->stack_top + 0] = value; - vm->stack_top += 1; -} - -static void vm_push_i32(struct VirtualMachine *vm, int32_t value) { - vm_push_u32(vm, (uint32_t)value); -} - -static void vm_push_u64(struct VirtualMachine *vm, uint64_t value) { - vm->stack[vm->stack_top + 0] = (uint32_t)(value >> 0); - vm->stack[vm->stack_top + 1] = (uint32_t)(value >> 32); - vm->stack_top += 2; -} - -static void vm_push_i64(struct VirtualMachine *vm, int64_t value) { - vm_push_u64(vm, (uint64_t)value); -} - -static void vm_push_f32(struct VirtualMachine *vm, float value) { - uint32_t integer; - memcpy(&integer, &value, sizeof(integer)); - vm_push_u32(vm, integer); -} - -static void vm_push_f64(struct VirtualMachine *vm, double value) { - uint64_t integer; - memcpy(&integer, &value, sizeof(integer)); - vm_push_u64(vm, integer); -} - -static uint32_t vm_pop_u32(struct VirtualMachine *vm) { - vm->stack_top -= 1; - return vm->stack[vm->stack_top + 0]; -} - -static int32_t vm_pop_i32(struct VirtualMachine *vm) { - return (int32_t)vm_pop_u32(vm); -} - -static uint64_t vm_pop_u64(struct VirtualMachine *vm) { - vm->stack_top -= 2; - return vm->stack[vm->stack_top + 0] | (uint64_t)vm->stack[vm->stack_top + 1] << 32; -} - -static int64_t vm_pop_i64(struct VirtualMachine *vm) { - return (int64_t)vm_pop_u64(vm); -} - -static float vm_pop_f32(struct VirtualMachine *vm) { - uint32_t integer = vm_pop_u32(vm); - float result; - memcpy(&result, &integer, sizeof(result)); - return result; -} - -static double vm_pop_f64(struct VirtualMachine *vm) { - uint64_t integer = vm_pop_u64(vm); - double result; - memcpy(&result, &integer, sizeof(result)); - return result; -} - -static void vm_callImport(struct VirtualMachine *vm, const struct Import *import) { - switch (import->mod) { - case ImpMod_wasi_snapshot_preview1: switch (import->name) { - case ImpName_fd_prestat_get: - { - uint32_t buf = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_prestat_get(vm, fd, buf)); - } - break; - case ImpName_fd_prestat_dir_name: - { - uint32_t path_len = vm_pop_u32(vm); - uint32_t path = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_prestat_dir_name(vm, fd, path, path_len)); - } - break; - case ImpName_fd_close: - { - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_close(vm, fd)); - } - break; - case ImpName_fd_read: - { - uint32_t nread = vm_pop_u32(vm); - uint32_t iovs_len = vm_pop_u32(vm); - uint32_t iovs = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_read(vm, fd, iovs, iovs_len, nread)); - } - break; - case ImpName_fd_filestat_get: - { - uint32_t buf = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_filestat_get(vm, fd, buf)); - } - break; - case ImpName_fd_filestat_set_size: - { - uint64_t size = vm_pop_u64(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_filestat_set_size(vm, fd, size)); - } - break; - case ImpName_fd_filestat_set_times: - { - panic("unexpected call to fd_filestat_set_times"); - } - break; - case ImpName_fd_fdstat_get: - { - uint32_t buf = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_fdstat_get(vm, fd, buf)); - } - break; - case ImpName_fd_readdir: - { - panic("unexpected call to fd_readdir"); - } - break; - case ImpName_fd_write: - { - uint32_t nwritten = vm_pop_u32(vm); - uint32_t iovs_len = vm_pop_u32(vm); - uint32_t iovs = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_write(vm, fd, iovs, iovs_len, nwritten)); - } - break; - case ImpName_fd_pwrite: - { - uint32_t nwritten = vm_pop_u32(vm); - uint64_t offset = vm_pop_u64(vm); - uint32_t iovs_len = vm_pop_u32(vm); - uint32_t iovs = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_fd_pwrite(vm, fd, iovs, iovs_len, offset, nwritten)); - } - break; - case ImpName_proc_exit: - { - uint32_t code = vm_pop_u32(vm); - exit(code); - } - break; - case ImpName_args_sizes_get: - { - uint32_t argv_buf_size = vm_pop_u32(vm); - uint32_t argc = vm_pop_u32(vm); - vm_push_u32(vm, wasi_args_sizes_get(vm, argc, argv_buf_size)); - } - break; - case ImpName_args_get: - { - uint32_t argv_buf = vm_pop_u32(vm); - uint32_t argv = vm_pop_u32(vm); - vm_push_u32(vm, wasi_args_get(vm, argv, argv_buf)); - } - break; - case ImpName_random_get: - { - uint32_t buf_len = vm_pop_u32(vm); - uint32_t buf = vm_pop_u32(vm); - vm_push_u32(vm, wasi_random_get(vm, buf, buf_len)); - } - break; - case ImpName_environ_sizes_get: - { - panic("unexpected call to environ_sizes_get"); - } - break; - case ImpName_environ_get: - { - panic("unexpected call to environ_get"); - } - break; - case ImpName_path_filestat_get: - { - uint32_t buf = vm_pop_u32(vm); - uint32_t path_len = vm_pop_u32(vm); - uint32_t path = vm_pop_u32(vm); - uint32_t flags = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_path_filestat_get(vm, fd, flags, path, path_len, buf)); - } - break; - case ImpName_path_create_directory: - { - uint32_t path_len = vm_pop_u32(vm); - uint32_t path = vm_pop_u32(vm); - int32_t fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_path_create_directory(vm, fd, path, path_len)); - } - break; - case ImpName_path_rename: - { - uint32_t new_path_len = vm_pop_u32(vm); - uint32_t new_path = vm_pop_u32(vm); - int32_t new_fd = vm_pop_i32(vm); - uint32_t old_path_len = vm_pop_u32(vm); - uint32_t old_path = vm_pop_u32(vm); - int32_t old_fd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_path_rename( - vm, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len - )); - } - break; - case ImpName_path_open: - { - uint32_t fd = vm_pop_u32(vm); - uint32_t fs_flags = vm_pop_u32(vm); - uint64_t fs_rights_inheriting = vm_pop_u64(vm); - uint64_t fs_rights_base = vm_pop_u64(vm); - uint32_t oflags = vm_pop_u32(vm); - uint32_t path_len = vm_pop_u32(vm); - uint32_t path = vm_pop_u32(vm); - uint32_t dirflags = vm_pop_u32(vm); - int32_t dirfd = vm_pop_i32(vm); - vm_push_u32(vm, wasi_path_open( - vm, - dirfd, - dirflags, - path, - path_len, - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd - )); - } - break; - case ImpName_path_remove_directory: - { - panic("unexpected call to path_remove_directory"); - } - break; - case ImpName_path_unlink_file: - { - panic("unexpected call to path_unlink_file"); - } - break; - case ImpName_clock_time_get: - { - uint32_t timestamp = vm_pop_u32(vm); - uint64_t precision = vm_pop_u64(vm); - uint32_t clock_id = vm_pop_u32(vm); - vm_push_u32(vm, wasi_clock_time_get(vm, clock_id, precision, timestamp)); - } - break; - case ImpName_fd_pread: - { - panic("unexpected call to fd_pread"); - } - break; - case ImpName_debug: - { - uint64_t number = vm_pop_u64(vm); - uint32_t text = vm_pop_u32(vm); - wasi_debug(vm, text, number); - } - break; - case ImpName_debug_slice: - { - uint32_t len = vm_pop_u32(vm); - uint32_t ptr = vm_pop_u32(vm); - wasi_debug_slice(vm, ptr, len); - } - break; - } - break; - } -} - -static void vm_call(struct VirtualMachine *vm, const struct Function *func) { - //struct TypeInfo *type_info = &vm->types[func->type_idx]; - //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_size: %u\n", - // func->id, type_info->param_count, type_info->result_count, func->locals_size); - - // Push zeroed locals to stack - memset(&vm->stack[vm->stack_top], 0, func->locals_size * sizeof(uint32_t)); - vm->stack_top += func->locals_size; - - vm_push_u32(vm, vm->pc.opcode); - vm_push_u32(vm, vm->pc.operand); - - vm->pc = func->entry_pc; -} - -static void vm_br_void(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand]; - - vm->stack_top -= stack_adjust; - - vm->pc.opcode = vm->operands[vm->pc.operand + 1]; - vm->pc.operand = vm->operands[vm->pc.operand + 2]; -} - -static void vm_br_u32(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand]; - - uint32_t result = vm_pop_u32(vm); - vm->stack_top -= stack_adjust; - vm_push_u32(vm, result); - - vm->pc.opcode = vm->operands[vm->pc.operand + 1]; - vm->pc.operand = vm->operands[vm->pc.operand + 2]; -} - -static void vm_br_u64(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand]; - - uint64_t result = vm_pop_u64(vm); - vm->stack_top -= stack_adjust; - vm_push_u64(vm, result); - - vm->pc.opcode = vm->operands[vm->pc.operand + 1]; - vm->pc.operand = vm->operands[vm->pc.operand + 2]; -} - -static void vm_return_void(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; - uint32_t frame_size = vm->operands[vm->pc.operand + 1]; - - vm->stack_top -= stack_adjust; - vm->pc.operand = vm_pop_u32(vm); - vm->pc.opcode = vm_pop_u32(vm); - - vm->stack_top -= frame_size; -} - -static void vm_return_u32(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; - uint32_t frame_size = vm->operands[vm->pc.operand + 1]; - - uint32_t result = vm_pop_u32(vm); - - vm->stack_top -= stack_adjust; - vm->pc.operand = vm_pop_u32(vm); - vm->pc.opcode = vm_pop_u32(vm); - - vm->stack_top -= frame_size; - vm_push_u32(vm, result); -} - -static void vm_return_u64(struct VirtualMachine *vm) { - uint32_t stack_adjust = vm->operands[vm->pc.operand + 0]; - uint32_t frame_size = vm->operands[vm->pc.operand + 1]; - - uint64_t result = vm_pop_u64(vm); - - vm->stack_top -= stack_adjust; - vm->pc.operand = vm_pop_u32(vm); - vm->pc.opcode = vm_pop_u32(vm); - - vm->stack_top -= frame_size; - vm_push_u64(vm, result); -} - -static void vm_run(struct VirtualMachine *vm) { - uint8_t *opcodes = vm->opcodes; - uint32_t *operands = vm->operands; - struct ProgramCounter *pc = &vm->pc; - uint32_t global_0 = vm->globals[0]; - for (;;) { - enum Op op = opcodes[pc->opcode]; - //fprintf(stderr, "stack[%u:%u]=%x:%x pc=%x:%x op=%u\n", - // vm->stack_top - 2, vm->stack_top - 1, - // vm->stack[vm->stack_top - 2], vm->stack[vm->stack_top - 1], - // pc->opcode, pc->operand, op); - pc->opcode += 1; - switch (op) { - case Op_unreachable: - panic("unreachable reached"); - case Op_br_void: - vm_br_void(vm); - break; - case Op_br_32: - vm_br_u32(vm); - break; - case Op_br_64: - vm_br_u64(vm); - break; - case Op_br_nez_void: - if (vm_pop_u32(vm) != 0) { - vm_br_void(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_nez_32: - if (vm_pop_u32(vm) != 0) { - vm_br_u32(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_nez_64: - if (vm_pop_u32(vm) != 0) { - vm_br_u64(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_eqz_void: - if (vm_pop_u32(vm) == 0) { - vm_br_void(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_eqz_32: - if (vm_pop_u32(vm) == 0) { - vm_br_u32(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_eqz_64: - if (vm_pop_u32(vm) == 0) { - vm_br_u64(vm); - } else { - pc->operand += 3; - } - break; - case Op_br_table_void: - { - uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); - pc->operand += 1 + index * 3; - vm_br_void(vm); - } - break; - case Op_br_table_32: - { - uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); - pc->operand += 1 + index * 3; - vm_br_u32(vm); - } - break; - case Op_br_table_64: - { - uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]); - pc->operand += 1 + index * 3; - vm_br_u64(vm); - } - break; - case Op_return_void: - vm_return_void(vm); - break; - case Op_return_32: - vm_return_u32(vm); - break; - case Op_return_64: - vm_return_u64(vm); - break; - case Op_call_import: - { - uint8_t import_idx = opcodes[pc->opcode]; - pc->opcode += 1; - vm_callImport(vm, &vm->imports[import_idx]); - } - break; - case Op_call_func: - { - uint32_t func_idx = operands[pc->operand]; - pc->operand += 1; - vm_call(vm, &vm->functions[func_idx]); - } - break; - case Op_call_indirect: - { - uint32_t fn_id = vm->table[vm_pop_u32(vm)]; - if (fn_id < vm->imports_len) - vm_callImport(vm, &vm->imports[fn_id]); - else - vm_call(vm, &vm->functions[fn_id - vm->imports_len]); - } - break; - - case Op_drop_32: - vm->stack_top -= 1; - break; - case Op_drop_64: - vm->stack_top -= 2; - break; - case Op_select_32: - { - uint32_t c = vm_pop_u32(vm); - uint32_t b = vm_pop_u32(vm); - uint32_t a = vm_pop_u32(vm); - uint32_t result = (c != 0) ? a : b; - vm_push_u32(vm, result); - } - break; - case Op_select_64: - { - uint32_t c = vm_pop_u32(vm); - uint64_t b = vm_pop_u64(vm); - uint64_t a = vm_pop_u64(vm); - uint64_t result = (c != 0) ? a : b; - vm_push_u64(vm, result); - } - break; - - case Op_local_get_32: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - vm_push_u32(vm, *local); - } - break; - case Op_local_get_64: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - vm_push_u64(vm, local[0] | (uint64_t)local[1] << 32); - } - break; - case Op_local_set_32: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - *local = vm_pop_u32(vm); - } - break; - case Op_local_set_64: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - uint64_t value = vm_pop_u64(vm); - local[0] = (uint32_t)(value >> 0); - local[1] = (uint32_t)(value >> 32); - } - break; - case Op_local_tee_32: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - *local = vm->stack[vm->stack_top - 1]; - } - break; - case Op_local_tee_64: - { - uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]]; - pc->operand += 1; - local[0] = vm->stack[vm->stack_top - 2]; - local[1] = vm->stack[vm->stack_top - 1]; - } - break; - - case Op_global_get_0_32: - vm_push_u32(vm, global_0); - break; - case Op_global_get_32: - { - uint32_t idx = operands[pc->operand]; - pc->operand += 1; - vm_push_u32(vm, vm->globals[idx]); - } - break; - case Op_global_set_0_32: - global_0 = vm_pop_u32(vm); - break; - case Op_global_set_32: - { - uint32_t idx = operands[pc->operand]; - pc->operand += 1; - vm->globals[idx] = vm_pop_u32(vm); - } - break; - - case Op_load_0_8: - { - uint32_t address = vm_pop_u32(vm); - vm_push_u32(vm, (uint8_t)vm->memory[address]); - } - break; - case Op_load_8: - { - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - vm_push_u32(vm, (uint8_t)vm->memory[address]); - } - break; - case Op_load_0_16: - { - uint32_t address = vm_pop_u32(vm); - vm_push_u32(vm, read_u16_le(&vm->memory[address])); - } - break; - case Op_load_16: - { - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - vm_push_u32(vm, read_u16_le(&vm->memory[address])); - } - break; - case Op_load_0_32: - { - uint32_t address = vm_pop_u32(vm); - vm_push_u32(vm, read_u32_le(&vm->memory[address])); - } - break; - case Op_load_32: - { - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - vm_push_u32(vm, read_u32_le(&vm->memory[address])); - } - break; - case Op_load_0_64: - { - uint32_t address = vm_pop_u32(vm); - vm_push_u64(vm, read_u64_le(&vm->memory[address])); - } - break; - case Op_load_64: - { - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - vm_push_u64(vm, read_u64_le(&vm->memory[address])); - } - break; - case Op_store_0_8: - { - uint8_t value = (uint8_t)vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm); - vm->memory[address] = value; - } - break; - case Op_store_8: - { - uint8_t value = (uint8_t)vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - vm->memory[address] = value; - } - break; - case Op_store_0_16: - { - uint16_t value = (uint16_t)vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm); - write_u16_le(&vm->memory[address], value); - } - break; - case Op_store_16: - { - uint16_t value = (uint16_t)vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - write_u16_le(&vm->memory[address], value); - } - break; - case Op_store_0_32: - { - uint32_t value = vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm); - write_u32_le(&vm->memory[address], value); - } - break; - case Op_store_32: - { - uint32_t value = vm_pop_u32(vm); - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - write_u32_le(&vm->memory[address], value); - } - break; - case Op_store_0_64: - { - uint64_t value = vm_pop_u64(vm); - uint32_t address = vm_pop_u32(vm); - write_u64_le(&vm->memory[address], value); - } - break; - case Op_store_64: - { - uint64_t value = vm_pop_u64(vm); - uint32_t address = vm_pop_u32(vm) + operands[pc->operand]; - pc->operand += 1; - write_u64_le(&vm->memory[address], value); - } - break; - case Op_mem_size: - vm_push_u32(vm, vm->memory_len / wasm_page_size); - break; - case Op_mem_grow: - { - uint32_t page_count = vm_pop_u32(vm); - uint32_t old_page_count = vm->memory_len / wasm_page_size; - uint32_t new_len = vm->memory_len + page_count * wasm_page_size; - if (new_len > max_memory) { - vm_push_i32(vm, -1); - } else { - vm->memory_len = new_len; - vm_push_u32(vm, old_page_count); - } - } - break; - - case Op_const_0_32: - vm_push_i32(vm, 0); - break; - case Op_const_0_64: - vm_push_i64(vm, 0); - break; - case Op_const_1_32: - vm_push_i32(vm, 1); - break; - case Op_const_1_64: - vm_push_i64(vm, 1); - break; - case Op_const_32: - { - uint32_t value = operands[pc->operand]; - pc->operand += 1; - vm_push_i32(vm, value); - } - break; - case Op_const_64: - { - uint64_t value = ((uint64_t)operands[pc->operand]) | - (((uint64_t)operands[pc->operand + 1]) << 32); - pc->operand += 2; - vm_push_i64(vm, value); - } - break; - case Op_const_umax_32: - vm_push_i32(vm, -1); - break; - case Op_const_umax_64: - vm_push_i64(vm, -1); - break; - - case Op_eqz_32: - { - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs == 0); - } - break; - case Op_eq_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case Op_ne_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case Op_slt_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case Op_ult_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case Op_sgt_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_ugt_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_sle_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_ule_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_sge_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case Op_uge_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - - case Op_eqz_64: - { - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs == 0); - } - break; - case Op_eq_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case Op_ne_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case Op_slt_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case Op_ult_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case Op_sgt_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_ugt_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_sle_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_ule_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_sge_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - case Op_uge_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - - case Op_feq_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case Op_fne_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case Op_flt_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs < rhs); - } - break; - case Op_fgt_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_fle_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_fge_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - - case Op_feq_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs == rhs); - } - break; - case Op_fne_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs != rhs); - } - break; - case Op_flt_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_fgt_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs > rhs); - } - break; - case Op_fle_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs <= rhs); - } - break; - case Op_fge_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_u32(vm, lhs >= rhs); - } - break; - - case Op_clz_32: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand); - vm_push_u32(vm, result); - } - break; - case Op_ctz_32: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand); - vm_push_u32(vm, result); - } - break; - case Op_popcnt_32: - { - uint32_t operand = vm_pop_u32(vm); - uint32_t result = __builtin_popcount(operand); - vm_push_u32(vm, result); - } - break; - case Op_add_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs + rhs); - } - break; - case Op_sub_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs - rhs); - } - break; - case Op_mul_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs * rhs); - } - break; - case Op_sdiv_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs / rhs); - } - break; - case Op_udiv_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs / rhs); - } - break; - case Op_srem_32: - { - int32_t rhs = vm_pop_i32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs % rhs); - } - break; - case Op_urem_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs % rhs); - } - break; - case Op_and_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs & rhs); - } - break; - case Op_or_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs | rhs); - } - break; - case Op_xor_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs ^ rhs); - } - break; - case Op_shl_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs << (rhs & 0x1f)); - } - break; - case Op_ashr_32: - { - uint32_t rhs = vm_pop_u32(vm); - int32_t lhs = vm_pop_i32(vm); - vm_push_i32(vm, lhs >> (rhs & 0x1f)); - } - break; - case Op_lshr_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, lhs >> (rhs & 0x1f)); - } - break; - case Op_rol_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, rotl32(lhs, rhs)); - } - break; - case Op_ror_32: - { - uint32_t rhs = vm_pop_u32(vm); - uint32_t lhs = vm_pop_u32(vm); - vm_push_u32(vm, rotr32(lhs, rhs)); - } - break; - - case Op_clz_64: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand); - vm_push_u64(vm, result); - } - break; - case Op_ctz_64: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand); - vm_push_u64(vm, result); - } - break; - case Op_popcnt_64: - { - uint64_t operand = vm_pop_u64(vm); - uint64_t result = __builtin_popcountll(operand); - vm_push_u64(vm, result); - } - break; - case Op_add_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs + rhs); - } - break; - case Op_sub_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs - rhs); - } - break; - case Op_mul_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs * rhs); - } - break; - case Op_sdiv_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs / rhs); - } - break; - case Op_udiv_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs / rhs); - } - break; - case Op_srem_64: - { - int64_t rhs = vm_pop_i64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs % rhs); - } - break; - case Op_urem_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs % rhs); - } - break; - case Op_and_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs & rhs); - } - break; - case Op_or_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs | rhs); - } - break; - case Op_xor_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs ^ rhs); - } - break; - case Op_shl_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs << (rhs & 0x3f)); - } - break; - case Op_ashr_64: - { - uint64_t rhs = vm_pop_u64(vm); - int64_t lhs = vm_pop_i64(vm); - vm_push_i64(vm, lhs >> (rhs & 0x3f)); - } - break; - case Op_lshr_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, lhs >> (rhs & 0x3f)); - } - break; - case Op_rol_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotl64(lhs, rhs)); - } - break; - case Op_ror_64: - { - uint64_t rhs = vm_pop_u64(vm); - uint64_t lhs = vm_pop_u64(vm); - vm_push_u64(vm, rotr64(lhs, rhs)); - } - break; - - case Op_fabs_32: - vm_push_f32(vm, fabsf(vm_pop_f32(vm))); - break; - case Op_fneg_32: - vm_push_f32(vm, -vm_pop_f32(vm)); - break; - case Op_ceil_32: - vm_push_f32(vm, ceilf(vm_pop_f32(vm))); - break; - case Op_floor_32: - vm_push_f32(vm, floorf(vm_pop_f32(vm))); - break; - case Op_trunc_32: - vm_push_f32(vm, truncf(vm_pop_f32(vm))); - break; - case Op_nearest_32: - vm_push_f32(vm, roundf(vm_pop_f32(vm))); - break; - case Op_sqrt_32: - vm_push_f32(vm, sqrtf(vm_pop_f32(vm))); - break; - case Op_fadd_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs + rhs); - } - break; - case Op_fsub_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs - rhs); - } - break; - case Op_fmul_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs * rhs); - } - break; - case Op_fdiv_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, lhs / rhs); - } - break; - case Op_fmin_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, fminf(lhs, rhs)); - } - break; - case Op_fmax_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, fmaxf(lhs, rhs)); - } - break; - case Op_copysign_32: - { - float rhs = vm_pop_f32(vm); - float lhs = vm_pop_f32(vm); - vm_push_f32(vm, copysignf(lhs, rhs)); - } - break; - - case Op_fabs_64: - vm_push_f64(vm, fabs(vm_pop_f64(vm))); - break; - case Op_fneg_64: - vm_push_f64(vm, -vm_pop_f64(vm)); - break; - case Op_ceil_64: - vm_push_f64(vm, ceil(vm_pop_f64(vm))); - break; - case Op_floor_64: - vm_push_f64(vm, floor(vm_pop_f64(vm))); - break; - case Op_trunc_64: - vm_push_f64(vm, trunc(vm_pop_f64(vm))); - break; - case Op_nearest_64: - vm_push_f64(vm, round(vm_pop_f64(vm))); - break; - case Op_sqrt_64: - vm_push_f64(vm, sqrt(vm_pop_f64(vm))); - break; - case Op_fadd_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs + rhs); - } - break; - case Op_fsub_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs - rhs); - } - break; - case Op_fmul_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs * rhs); - } - break; - case Op_fdiv_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, lhs / rhs); - } - break; - case Op_fmin_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, fmin(lhs, rhs)); - } - break; - case Op_fmax_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, fmax(lhs, rhs)); - } - break; - case Op_copysign_64: - { - double rhs = vm_pop_f64(vm); - double lhs = vm_pop_f64(vm); - vm_push_f64(vm, copysign(lhs, rhs)); - } - break; - - case Op_ftos_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break; - case Op_ftou_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break; - case Op_ftos_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break; - case Op_ftou_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break; - case Op_sext_64_32: vm_push_i64(vm, vm_pop_i32(vm)); break; - case Op_ftos_64_32: vm_push_i64(vm, (int64_t)vm_pop_f32(vm)); break; - case Op_ftou_64_32: vm_push_u64(vm, (uint64_t)vm_pop_f32(vm)); break; - case Op_ftos_64_64: vm_push_i64(vm, (int64_t)vm_pop_f64(vm)); break; - case Op_ftou_64_64: vm_push_u64(vm, (uint64_t)vm_pop_f64(vm)); break; - case Op_stof_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break; - case Op_utof_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break; - case Op_stof_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break; - case Op_utof_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break; - case Op_ftof_32_64: vm_push_f32(vm, (float)vm_pop_f64(vm)); break; - case Op_stof_64_32: vm_push_f64(vm, (double)vm_pop_i32(vm)); break; - case Op_utof_64_32: vm_push_f64(vm, (double)vm_pop_u32(vm)); break; - case Op_stof_64_64: vm_push_f64(vm, (double)vm_pop_i64(vm)); break; - case Op_utof_64_64: vm_push_f64(vm, (double)vm_pop_u64(vm)); break; - case Op_ftof_64_32: vm_push_f64(vm, (double)vm_pop_f32(vm)); break; - case Op_sext8_32: vm_push_i32(vm, (int8_t)vm_pop_i32(vm)); break; - case Op_sext16_32: vm_push_i32(vm, (int16_t)vm_pop_i32(vm)); break; - case Op_sext8_64: vm_push_i64(vm, (int8_t)vm_pop_i64(vm)); break; - case Op_sext16_64: vm_push_i64(vm, (int16_t)vm_pop_i64(vm)); break; - case Op_sext32_64: vm_push_i64(vm, (int32_t)vm_pop_i64(vm)); break; - - case Op_memcpy: - { - uint32_t n = vm_pop_u32(vm); - uint32_t src = vm_pop_u32(vm); - uint32_t dest = vm_pop_u32(vm); - assert(dest + n <= vm->memory_len); - assert(src + n <= vm->memory_len); - assert(src + n <= dest || dest + n <= src); // overlapping - memcpy(vm->memory + dest, vm->memory + src, n); - } - break; - case Op_memset: - { - uint32_t n = vm_pop_u32(vm); - uint8_t value = (uint8_t)vm_pop_u32(vm); - uint32_t dest = vm_pop_u32(vm); - assert(dest + n <= vm->memory_len); - memset(vm->memory + dest, value, n); - } - break; - } - } -} - -static size_t common_prefix(const char *a, const char *b) { - size_t i = 0; - for (; a[i] == b[i]; i += 1) {} - return i; -} - -int main(int argc, char **argv) { - char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - - const char *zig_lib_dir_path = argv[1]; - const char *cmake_binary_dir_path = argv[2]; - const char *root_name = argv[3]; - size_t argv_i = 4; - const char *wasm_file = argv[argv_i]; - - size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path); - const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len; - - size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path); - - const char *new_argv[30]; - char new_argv_buf[PATH_MAX + 1024]; - uint32_t new_argv_i = 0; - uint32_t new_argv_buf_i = 0; - - int cache_dir = -1; - { - char cache_dir_buf[PATH_MAX * 2]; - size_t i = 0; - size_t cmake_binary_dir_path_len = strlen(cmake_binary_dir_path); - - memcpy(cache_dir_buf + i, cmake_binary_dir_path, cmake_binary_dir_path_len); - i += cmake_binary_dir_path_len; - - cache_dir_buf[i] = '/'; - i += 1; - - memcpy(cache_dir_buf + i, "zig1-cache", strlen("zig1-cache")); - i += strlen("zig1-cache"); - - cache_dir_buf[i] = 0; - - mkdir(cache_dir_buf, 0777); - cache_dir = err_wrap("opening cache dir", - open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC)); - } - - // Construct a new argv for the WASI code which has absolute paths - // converted to relative paths, and has the target and terminal status - // autodetected. - - // wasm file path - new_argv[new_argv_i] = argv[argv_i]; - new_argv_i += 1; - argv_i += 1; - - for (; argv[argv_i]; argv_i += 1) { - new_argv[new_argv_i] = argv[argv_i]; - new_argv_i += 1; - } - - { - new_argv[new_argv_i] = "--name"; - new_argv_i += 1; - - new_argv[new_argv_i] = root_name; - new_argv_i += 1; - - char *emit_bin_arg = new_argv_buf + new_argv_buf_i; - memcpy(new_argv_buf + new_argv_buf_i, "-femit-bin=", strlen("-femit-bin=")); - new_argv_buf_i += strlen("-femit-bin="); - memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len); - new_argv_buf_i += rel_cmake_bin_path_len; - new_argv_buf[new_argv_buf_i] = '/'; - new_argv_buf_i += 1; - memcpy(new_argv_buf + new_argv_buf_i, root_name, strlen(root_name)); - new_argv_buf_i += strlen(root_name); - memcpy(new_argv_buf + new_argv_buf_i, ".c", 3); - new_argv_buf_i += 3; - - new_argv[new_argv_i] = emit_bin_arg; - new_argv_i += 1; - } - - { - new_argv[new_argv_i] = "--pkg-begin"; - new_argv_i += 1; - - new_argv[new_argv_i] = "build_options"; - new_argv_i += 1; - - char *build_options_path = new_argv_buf + new_argv_buf_i; - memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len); - new_argv_buf_i += rel_cmake_bin_path_len; - new_argv_buf[new_argv_buf_i] = '/'; - new_argv_buf_i += 1; - memcpy(new_argv_buf + new_argv_buf_i, "config.zig", strlen("config.zig")); - new_argv_buf_i += strlen("config.zig"); - new_argv_buf[new_argv_buf_i] = 0; - new_argv_buf_i += 1; - - new_argv[new_argv_i] = build_options_path; - new_argv_i += 1; - - new_argv[new_argv_i] = "--pkg-end"; - new_argv_i += 1; - } - - { - new_argv[new_argv_i] = "-target"; - new_argv_i += 1; - - new_argv[new_argv_i] = ZIG_TRIPLE_ARCH "-" ZIG_TRIPLE_OS; - new_argv_i += 1; - } - - if (isatty(STDERR_FILENO) != 0) { - new_argv[new_argv_i] = "--color"; - new_argv_i += 1; - - new_argv[new_argv_i] = "on"; - new_argv_i += 1; - } - - new_argv[new_argv_i] = NULL; - - const struct ByteSlice compressed_bytes = read_file_alloc(wasm_file); - - const size_t max_uncompressed_size = 2500000; - char *mod_ptr = arena_alloc(max_uncompressed_size); - size_t mod_len = ZSTD_decompress(mod_ptr, max_uncompressed_size, - compressed_bytes.ptr, compressed_bytes.len); - - int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC)); - int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC)); - - add_preopen(0, "stdin", STDIN_FILENO); - add_preopen(1, "stdout", STDOUT_FILENO); - add_preopen(2, "stderr", STDERR_FILENO); - add_preopen(3, ".", cwd); - add_preopen(4, "/cache", cache_dir); - add_preopen(5, "/lib", zig_lib_dir); - - uint32_t i = 0; - - if (mod_ptr[0] != 0 || mod_ptr[1] != 'a' || mod_ptr[2] != 's' || mod_ptr[3] != 'm') { - panic("bad magic"); - } - i += 4; - - uint32_t version = read_u32_le(mod_ptr + i); - i += 4; - if (version != 1) panic("bad wasm version"); - - uint32_t section_starts[13]; - memset(§ion_starts, 0, sizeof(uint32_t) * 13); - - while (i < mod_len) { - uint8_t section_id = mod_ptr[i]; - i += 1; - uint32_t section_len = read32_uleb128(mod_ptr, &i); - section_starts[section_id] = i; - i += section_len; - } - - // Map type indexes to offsets into the module. - struct TypeInfo *types; - { - i = section_starts[Section_type]; - uint32_t types_len = read32_uleb128(mod_ptr, &i); - types = arena_alloc(sizeof(struct TypeInfo) * types_len); - for (size_t type_i = 0; type_i < types_len; type_i += 1) { - struct TypeInfo *info = &types[type_i]; - if (mod_ptr[i] != 0x60) panic("bad type byte"); - i += 1; - - info->param_count = read32_uleb128(mod_ptr, &i); - if (info->param_count > 32) panic("found a type with over 32 parameters"); - info->param_types = 0; - for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { - int64_t param_type = read64_ileb128(mod_ptr, &i); - switch (param_type) { - case -1: case -3: bs_unset(&info->param_types, param_i); break; - case -2: case -4: bs_set(&info->param_types, param_i); break; - default: panic("unexpected param type"); - } - } - - info->result_count = read32_uleb128(mod_ptr, &i); - info->result_types = 0; - for (uint32_t result_i = 0; result_i < info->result_count; result_i += 1) { - int64_t result_type = read64_ileb128(mod_ptr, &i); - switch (result_type) { - case -1: case -3: bs_unset(&info->result_types, result_i); break; - case -2: case -4: bs_set(&info->result_types, result_i); break; - default: panic("unexpected result type"); - } - } - } - } - - // Count the imported functions so we can correct function references. - struct Import *imports; - uint32_t imports_len; - { - i = section_starts[Section_import]; - imports_len = read32_uleb128(mod_ptr, &i); - imports = arena_alloc(sizeof(struct Import) * imports_len); - for (size_t imp_i = 0; imp_i < imports_len; imp_i += 1) { - struct Import *imp = &imports[imp_i]; - - struct ByteSlice mod_name = read_name(mod_ptr, &i); - if (mod_name.len == strlen("wasi_snapshot_preview1") && - memcmp(mod_name.ptr, "wasi_snapshot_preview1", mod_name.len) == 0) { - imp->mod = ImpMod_wasi_snapshot_preview1; - } else panic("unknown import module"); - - struct ByteSlice sym_name = read_name(mod_ptr, &i); - if (sym_name.len == strlen("args_get") && - memcmp(sym_name.ptr, "args_get", sym_name.len) == 0) { - imp->name = ImpName_args_get; - } else if (sym_name.len == strlen("args_sizes_get") && - memcmp(sym_name.ptr, "args_sizes_get", sym_name.len) == 0) { - imp->name = ImpName_args_sizes_get; - } else if (sym_name.len == strlen("clock_time_get") && - memcmp(sym_name.ptr, "clock_time_get", sym_name.len) == 0) { - imp->name = ImpName_clock_time_get; - } else if (sym_name.len == strlen("debug") && - memcmp(sym_name.ptr, "debug", sym_name.len) == 0) { - imp->name = ImpName_debug; - } else if (sym_name.len == strlen("debug_slice") && - memcmp(sym_name.ptr, "debug_slice", sym_name.len) == 0) { - imp->name = ImpName_debug_slice; - } else if (sym_name.len == strlen("environ_get") && - memcmp(sym_name.ptr, "environ_get", sym_name.len) == 0) { - imp->name = ImpName_environ_get; - } else if (sym_name.len == strlen("environ_sizes_get") && - memcmp(sym_name.ptr, "environ_sizes_get", sym_name.len) == 0) { - imp->name = ImpName_environ_sizes_get; - } else if (sym_name.len == strlen("fd_close") && - memcmp(sym_name.ptr, "fd_close", sym_name.len) == 0) { - imp->name = ImpName_fd_close; - } else if (sym_name.len == strlen("fd_fdstat_get") && - memcmp(sym_name.ptr, "fd_fdstat_get", sym_name.len) == 0) { - imp->name = ImpName_fd_fdstat_get; - } else if (sym_name.len == strlen("fd_filestat_get") && - memcmp(sym_name.ptr, "fd_filestat_get", sym_name.len) == 0) { - imp->name = ImpName_fd_filestat_get; - } else if (sym_name.len == strlen("fd_filestat_set_size") && - memcmp(sym_name.ptr, "fd_filestat_set_size", sym_name.len) == 0) { - imp->name = ImpName_fd_filestat_set_size; - } else if (sym_name.len == strlen("fd_filestat_set_times") && - memcmp(sym_name.ptr, "fd_filestat_set_times", sym_name.len) == 0) { - imp->name = ImpName_fd_filestat_set_times; - } else if (sym_name.len == strlen("fd_pread") && - memcmp(sym_name.ptr, "fd_pread", sym_name.len) == 0) { - imp->name = ImpName_fd_pread; - } else if (sym_name.len == strlen("fd_prestat_dir_name") && - memcmp(sym_name.ptr, "fd_prestat_dir_name", sym_name.len) == 0) { - imp->name = ImpName_fd_prestat_dir_name; - } else if (sym_name.len == strlen("fd_prestat_get") && - memcmp(sym_name.ptr, "fd_prestat_get", sym_name.len) == 0) { - imp->name = ImpName_fd_prestat_get; - } else if (sym_name.len == strlen("fd_pwrite") && - memcmp(sym_name.ptr, "fd_pwrite", sym_name.len) == 0) { - imp->name = ImpName_fd_pwrite; - } else if (sym_name.len == strlen("fd_read") && - memcmp(sym_name.ptr, "fd_read", sym_name.len) == 0) { - imp->name = ImpName_fd_read; - } else if (sym_name.len == strlen("fd_readdir") && - memcmp(sym_name.ptr, "fd_readdir", sym_name.len) == 0) { - imp->name = ImpName_fd_readdir; - } else if (sym_name.len == strlen("fd_write") && - memcmp(sym_name.ptr, "fd_write", sym_name.len) == 0) { - imp->name = ImpName_fd_write; - } else if (sym_name.len == strlen("path_create_directory") && - memcmp(sym_name.ptr, "path_create_directory", sym_name.len) == 0) { - imp->name = ImpName_path_create_directory; - } else if (sym_name.len == strlen("path_filestat_get") && - memcmp(sym_name.ptr, "path_filestat_get", sym_name.len) == 0) { - imp->name = ImpName_path_filestat_get; - } else if (sym_name.len == strlen("path_open") && - memcmp(sym_name.ptr, "path_open", sym_name.len) == 0) { - imp->name = ImpName_path_open; - } else if (sym_name.len == strlen("path_remove_directory") && - memcmp(sym_name.ptr, "path_remove_directory", sym_name.len) == 0) { - imp->name = ImpName_path_remove_directory; - } else if (sym_name.len == strlen("path_rename") && - memcmp(sym_name.ptr, "path_rename", sym_name.len) == 0) { - imp->name = ImpName_path_rename; - } else if (sym_name.len == strlen("path_unlink_file") && - memcmp(sym_name.ptr, "path_unlink_file", sym_name.len) == 0) { - imp->name = ImpName_path_unlink_file; - } else if (sym_name.len == strlen("proc_exit") && - memcmp(sym_name.ptr, "proc_exit", sym_name.len) == 0) { - imp->name = ImpName_proc_exit; - } else if (sym_name.len == strlen("random_get") && - memcmp(sym_name.ptr, "random_get", sym_name.len) == 0) { - imp->name = ImpName_random_get; - } else panic("unknown import name"); - - uint32_t desc = read32_uleb128(mod_ptr, &i); - if (desc != 0) panic("external kind not function"); - imp->type_idx = read32_uleb128(mod_ptr, &i); - } - } - - // Find _start in the exports - uint32_t start_fn_idx; - { - i = section_starts[Section_export]; - uint32_t count = read32_uleb128(mod_ptr, &i); - for (; count > 0; count -= 1) { - struct ByteSlice name = read_name(mod_ptr, &i); - uint32_t desc = read32_uleb128(mod_ptr, &i); - start_fn_idx = read32_uleb128(mod_ptr, &i); - if (desc == 0 && name.len == strlen("_start") && - memcmp(name.ptr, "_start", name.len) == 0) - { - break; - } - } - if (count == 0) panic("_start symbol not found"); - } - - // Map function indexes to offsets into the module and type index. - struct Function *functions; - uint32_t functions_len; - { - i = section_starts[Section_function]; - functions_len = read32_uleb128(mod_ptr, &i); - functions = arena_alloc(sizeof(struct Function) * functions_len); - for (size_t func_i = 0; func_i < functions_len; func_i += 1) { - struct Function *func = &functions[func_i]; - func->id = imports_len + func_i; - func->type_idx = read32_uleb128(mod_ptr, &i); - } - } - - // Allocate and initialize globals. - uint64_t *globals; - { - i = section_starts[Section_global]; - uint32_t globals_len = read32_uleb128(mod_ptr, &i); - globals = arena_alloc(sizeof(uint64_t) * globals_len); - for (size_t glob_i = 0; glob_i < globals_len; glob_i += 1) { - uint64_t *global = &globals[glob_i]; - uint32_t content_type = read32_uleb128(mod_ptr, &i); - uint32_t mutability = read32_uleb128(mod_ptr, &i); - if (mutability != 1) panic("expected mutable global"); - if (content_type != 0x7f) panic("unexpected content type"); - uint8_t opcode = mod_ptr[i]; - i += 1; - if (opcode != WasmOp_i32_const) panic("expected i32_const op"); - uint32_t init = read32_ileb128(mod_ptr, &i); - *global = (uint32_t)init; - } - } - - // Allocate and initialize memory. - uint32_t memory_len; - { - i = section_starts[Section_memory]; - uint32_t memories_len = read32_uleb128(mod_ptr, &i); - if (memories_len != 1) panic("unexpected memory count"); - uint32_t flags = read32_uleb128(mod_ptr, &i); - (void)flags; - memory_len = read32_uleb128(mod_ptr, &i) * wasm_page_size; - - i = section_starts[Section_data]; - uint32_t datas_count = read32_uleb128(mod_ptr, &i); - for (; datas_count > 0; datas_count -= 1) { - uint32_t mode = read32_uleb128(mod_ptr, &i); - if (mode != 0) panic("expected mode 0"); - enum WasmOp opcode = mod_ptr[i]; - i += 1; - if (opcode != WasmOp_i32_const) panic("expected opcode i32_const"); - uint32_t offset = read32_uleb128(mod_ptr, &i); - enum WasmOp end = mod_ptr[i]; - if (end != WasmOp_end) panic("expected end opcode"); - i += 1; - uint32_t bytes_len = read32_uleb128(mod_ptr, &i); - memcpy(memory + offset, mod_ptr + i, bytes_len); - i += bytes_len; - } - } - - uint32_t *table = NULL; - { - i = section_starts[Section_table]; - uint32_t table_count = read32_uleb128(mod_ptr, &i); - if (table_count > 1) { - panic("expected only one table section"); - } else if (table_count == 1) { - uint32_t element_type = read32_uleb128(mod_ptr, &i); - (void)element_type; - uint32_t has_max = read32_uleb128(mod_ptr, &i); - if (has_max != 1) panic("expected has_max==1"); - uint32_t initial = read32_uleb128(mod_ptr, &i); - (void)initial; - uint32_t maximum = read32_uleb128(mod_ptr, &i); - - i = section_starts[Section_element]; - uint32_t element_section_count = read32_uleb128(mod_ptr, &i); - if (element_section_count != 1) panic("expected one element section"); - uint32_t flags = read32_uleb128(mod_ptr, &i); - (void)flags; - enum WasmOp opcode = mod_ptr[i]; - i += 1; - if (opcode != WasmOp_i32_const) panic("expected op i32_const"); - uint32_t offset = read32_uleb128(mod_ptr, &i); - enum WasmOp end = mod_ptr[i]; - if (end != WasmOp_end) panic("expected op end"); - i += 1; - uint32_t elem_count = read32_uleb128(mod_ptr, &i); - - table = arena_alloc(sizeof(uint32_t) * maximum); - memset(table, 0, sizeof(uint32_t) * maximum); - - for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { - table[elem_i + offset] = read32_uleb128(mod_ptr, &i); - } - } - } - - struct VirtualMachine vm; -#ifndef NDEBUG - memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version -#endif - vm.stack = arena_alloc(sizeof(uint32_t) * 10000000), - vm.mod_ptr = mod_ptr; - vm.opcodes = arena_alloc(2000000); - vm.operands = arena_alloc(sizeof(uint32_t) * 2000000); - vm.stack_top = 0; - vm.functions = functions; - vm.types = types; - vm.globals = globals; - vm.memory = memory; - vm.memory_len = memory_len; - vm.imports = imports; - vm.imports_len = imports_len; - vm.args = new_argv; - vm.table = table; - - { - uint32_t code_i = section_starts[Section_code]; - uint32_t codes_len = read32_uleb128(mod_ptr, &code_i); - if (codes_len != functions_len) panic("code/function length mismatch"); - struct ProgramCounter pc; - pc.opcode = 0; - pc.operand = 0; - struct StackInfo stack; - for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) { - struct Function *func = &functions[func_i]; - uint32_t size = read32_uleb128(mod_ptr, &code_i); - uint32_t code_begin = code_i; - - stack.top_index = 0; - stack.top_offset = 0; - struct TypeInfo *type_info = &vm.types[func->type_idx]; - for (uint32_t param_i = 0; param_i < type_info->param_count; param_i += 1) - si_push(&stack, bs_isSet(&type_info->param_types, param_i)); - uint32_t params_size = stack.top_offset; - - for (uint32_t local_sets_count = read32_uleb128(mod_ptr, &code_i); - local_sets_count > 0; local_sets_count -= 1) - { - uint32_t local_set_count = read32_uleb128(mod_ptr, &code_i); - enum StackType local_type; - switch (read64_ileb128(mod_ptr, &code_i)) { - case -1: case -3: local_type = ST_32; break; - case -2: case -4: local_type = ST_64; break; - default: panic("unexpected local type"); - } - for (; local_set_count > 0; local_set_count -= 1) - si_push(&stack, local_type); - } - func->locals_size = stack.top_offset - params_size; - - func->entry_pc = pc; - //fprintf(stderr, "decoding func id %u with pc %u:%u\n", func->id, pc.opcode, pc.operand); - vm_decodeCode(&vm, type_info, &code_i, &pc, &stack); - if (code_i != code_begin + size) panic("bad code size"); - } - //fprintf(stderr, "%u opcodes\n%u operands\n", pc.opcode, pc.operand); - } - - vm_call(&vm, &vm.functions[start_fn_idx - imports_len]); - vm_run(&vm); - - return 0; -} From e000db278295e6ca61e1d078ae32f83a9abca6da Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 30 Nov 2022 01:26:25 -0500 Subject: [PATCH 31/68] wasi: implement file truncation The way this is implemented destroys the contents of the file, so revisit if this causes issues in the future. --- stage1/wasi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/stage1/wasi.c b/stage1/wasi.c index 8ff04d5ef43f..c378fc3a20dc 100644 --- a/stage1/wasi.c +++ b/stage1/wasi.c @@ -555,10 +555,17 @@ uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io; long old_size = ftell(fds[fd].stream); if (old_size < 0) return wasi_errno_io; - if (size > (unsigned long)old_size) { - if (fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io; - fputc(0, fds[fd].stream); - } else if (size < (unsigned long)old_size) panic("unimplemented"); + if (size != (unsigned long)old_size) { + if (size > 0 && fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io; + if (size < (unsigned long)old_size) { + // Note that this destroys the contents on resize might have to save truncated + // file in memory if this becomes an issue. + FILE *trunc = fopen(des[fds[fd].de].host_path, "wb"); + if (trunc == NULL) return wasi_errno_io; + fclose(trunc); + } + if (size > 0) fputc(0, fds[fd].stream); + } if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; return wasi_errno_success; } From 1e638cb206ffe0cd910e6e4803557e70366fef4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 4 Dec 2022 16:45:15 -0700 Subject: [PATCH 32/68] CMake adjustments --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bc2ae9dd4d1..fafdee7d19c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -715,8 +715,8 @@ if(MSVC) set(ZIG2_LINK_FLAGS "/STACK:16777216") else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") - set(ZIG1_COMPILE_FLAGS "-std=c99") - set(ZIG2_COMPILE_FLAGS "-std=c99") + set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() @@ -740,9 +740,7 @@ add_custom_command( ) add_executable(zig1 ${ZIG1_C_SOURCE} "${CMAKE_SOURCE_DIR}/stage1/wasi.c") -set_target_properties(zig1 PROPERTIES - COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS} - LINK_FLAGS ${ZIG2_LINK_FLAGS}) +set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) target_link_libraries(zig1 LINK_PUBLIC m) target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) @@ -762,7 +760,7 @@ add_custom_command( OUTPUT "${ZIG2_C_SOURCE}" COMMAND zig1 ${BUILD_ZIG2_ARGS} DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" - COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG2_C_SOURCE}" + COMMENT STATUS "Running zig1.wasm to produce ${ZIG2_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) @@ -780,7 +778,7 @@ add_custom_command( OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" - COMMENT STATUS "Interpreting zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" + COMMENT STATUS "Running zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) From 54b960aa4dc335a9f9c6985ac869dd88fdf2321a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 4 Dec 2022 17:15:53 -0700 Subject: [PATCH 33/68] CMake: add the bracket-depth workaround for zig1 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fafdee7d19c0..31903cb4ff92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -717,6 +717,9 @@ else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -fbracket-depth=512") + endif() set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() From ce4e5fee6346d142a7a98d5c56a056ff8a25e1f1 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 4 Dec 2022 23:50:11 -0500 Subject: [PATCH 34/68] wasm2c: avoid aliasing issues on memory access --- stage1/wasm2c.c | 382 +++++++++++++++++++++--------------------------- 1 file changed, 170 insertions(+), 212 deletions(-) diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c index 1e0fb46bff7f..30258bd73613 100644 --- a/stage1/wasm2c.c +++ b/stage1/wasm2c.c @@ -78,7 +78,7 @@ int main(int argc, char **argv) { } const char *mod = "wasm"; - bool isBigEndian = false; // TODO + bool is_big_endian = false; // TODO struct InputStream in; InputStream_open(&in, argv[1]); @@ -95,6 +95,112 @@ int main(int argc, char **argv) { "#include \n" "#include \n" "#include \n" + "\n", out); + if (is_big_endian) + fputs("static uint16_t i16_byteswap(uint16_t src) {\n" + " return (uint16_t)(uint8_t)(src >> 0) << 8 |\n" + " (uint16_t)(uint8_t)(src >> 8) << 0;\n" + "}\n" + "static uint32_t i32_byteswap(uint32_t src) {\n" + " return (uint32_t)i16_byteswap(src >> 0) << 16 |\n" + " (uint32_t)i16_byteswap(src >> 16) << 0;\n" + "}\n" + "static uint64_t i64_byteswap(uint64_t src) {\n" + " return (uint64_t)i32_byteswap(src >> 0) << 32 |\n" + " (uint64_t)i32_byteswap(src >> 32) << 0;\n" + "}\n" + "\n", out); + fputs("static uint16_t load16_align0(const uint8_t *ptr) {\n" + " uint16_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint16_t load16_align1(const uint16_t *ptr) {\n" + " uint16_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align0(const uint8_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align1(const uint16_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align2(const uint32_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align0(const uint8_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align1(const uint16_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align2(const uint32_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align3(const uint64_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "\n" + "static void store16_align0(uint8_t *ptr, uint16_t val) {\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store16_align1(uint16_t *ptr, uint16_t val) {\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align0(uint8_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align1(uint16_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align2(uint32_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align0(uint8_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align1(uint16_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align2(uint32_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align3(uint64_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" "\n" "static uint32_t i32_reinterpret_f32(const float src) {\n" " uint32_t dst;\n" @@ -912,18 +1018,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i32); - if (align < 2 || isBigEndian) { - fseek(out, -1, SEEK_CUR); - fputc('\n', out); - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32 + "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -933,18 +1030,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i64); - if (align < 3 || isBigEndian) { - fseek(out, -1, SEEK_CUR); - fputc('\n', out); - for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - } else fprintf(out, "*(const uint64_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "load64_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32 + "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -954,18 +1042,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_f32); - if (align < 2 || isBigEndian) { - fputs("f32_reinterpret_i32(\n", out); - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - fputc(')', out); - } else fprintf(out, "*(const float *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "f32_reinterpret_i32(load32_align%" PRIu32 "((const uint%" PRIu32 + "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n", + align, 8 << align, 0, base, offset); } break; } @@ -975,18 +1054,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_f64); - if (align < 3 || isBigEndian) { - fputs("f64_reinterpret_i64(\n", out); - for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - fputc(')', out); - } else fprintf(out, "*(const double *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "f64_reinterpret_i64(load64_align%" PRIu32 "((const uint%" PRIu32 + "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n", + align, 8 << align, 0, base, offset); } break; } @@ -1018,18 +1088,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i32); - if (align < 1 || isBigEndian) { - fputs("(int16_t)(\n", out); - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - fputc(')', out); - } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1039,18 +1100,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i32); - if (align < 1 || isBigEndian) { - fseek(out, -1, SEEK_CUR); - fputc('\n', out); - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1082,18 +1134,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i64); - if (align < 1 || isBigEndian) { - fputs("(int16_t)(\n", out); - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - fputc(')', out); - } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1103,18 +1146,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i64); - if (align < 1 || isBigEndian) { - fseek(out, -1, SEEK_CUR); - fputc('\n', out); - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1124,18 +1158,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i64); - if (align < 2 || isBigEndian) { - fputs("(int32_t)(\n", out); - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - fputc(')', out); - } else fprintf(out, "*(const int32_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "(int32_t)load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1145,18 +1170,9 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t base = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i64); - if (align < 2 || isBigEndian) { - fseek(out, -1, SEEK_CUR); - fputc('\n', out); - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - if (byte_i > 0) fputs(" |\n", out); - FuncGen_cont(&fg, out); - fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" - PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3); - } - } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")]", 0, base, offset); - fputs(";\n", out); + fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); } break; } @@ -1167,19 +1183,10 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 2 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(l%" PRIu32 " >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1189,19 +1196,10 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 3 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(l%" PRIu32 " >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(uint64_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1211,19 +1209,11 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 2 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(i32_reinterpret_f32(l%" PRIu32 ") >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(float *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "i32_reinterpret_f32(l%" PRIu32 "));\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1233,19 +1223,11 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 3 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(i64_reinterpret_f64(l%" PRIu32 ") >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(double *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "i64_reinterpret_f64(l%" PRIu32 "));\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1267,19 +1249,11 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 1 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(l%" PRIu32 " >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint16_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1301,19 +1275,11 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 1 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(l%" PRIu32 " >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint16_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); } break; } @@ -1323,19 +1289,11 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t value = FuncGen_stackPop(&fg); uint32_t base = FuncGen_stackPop(&fg); - if (align < 2 || isBigEndian) { - for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) { - FuncGen_indent(&fg, out); - fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = " - "(uint8_t)(l%" PRIu32 " >> %2u);\n", - 0, base, offset + byte_i, value, byte_i << 3); - } - } else { - FuncGen_indent(&fg, out); - fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32 - " + UINT32_C(%" PRIu32 ")] = (uint32_t)l%" PRIu32 ";\n", - 0, base, offset, value); - } + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint32_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); } break; } From f421efbcc1eebfca5a723a5d4ee5aa685bcc10d8 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 4 Dec 2022 23:50:28 -0500 Subject: [PATCH 35/68] CBE: fix bad local reuse for volatile memset --- src/codegen/c.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a569e47401f6..f32d53ef0d4c 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -5935,16 +5935,15 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { const dest_ptr = try f.resolveInst(pl_op.operand); const value = try f.resolveInst(extra.lhs); const len = try f.resolveInst(extra.rhs); - try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); const writer = f.object.writer(); if (dest_ty.isVolatilePtr()) { var u8_ptr_pl = dest_ty.ptrInfo(); u8_ptr_pl.data.pointee_type = Type.u8; const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + const index = try f.allocLocal(inst, Type.usize); try writer.writeAll("for ("); - const index = try f.allocLocal(inst, Type.usize); try f.writeCValue(writer, index, .Other); try writer.writeAll(" = "); try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer); @@ -5966,11 +5965,13 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(writer, value, .FunctionArgument); try writer.writeAll(";\n"); + try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); try freeLocal(f, inst, index.local, 0); return CValue.none; } + try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); try writer.writeAll("memset("); try f.writeCValue(writer, dest_ptr, .FunctionArgument); try writer.writeAll(", "); From 687ea31ef9c086db12421e3d4dd364fa040c8ea6 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 01:52:24 -0500 Subject: [PATCH 36/68] cmake: fix host target detection --- CMakeLists.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31903cb4ff92..7d2e9d89e61a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -723,7 +723,20 @@ else() set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") endif() -string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}-${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_TRIPLE) +if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(HOST_TARGET_ARCH "x86_64") +elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + set(HOST_TARGET_ARCH "aarch64") +else() + string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" HOST_TARGET_ARCH) +endif() +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(HOST_TARGET_OS "macos") +else() + string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_OS) +endif() +set(HOST_TARGET_TRIPLE "${HOST_TARGET_ARCH}-${HOST_TARGET_OS}") + set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c") set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") From 47a2a526e252c699f664c86ba107fccac948f3aa Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 01:52:54 -0500 Subject: [PATCH 37/68] test: remove reference to stage1 --- src/test.zig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test.zig b/src/test.zig index de0efc359d78..56abe248b3c1 100644 --- a/src/test.zig +++ b/src/test.zig @@ -20,15 +20,11 @@ const enable_wasmtime: bool = build_options.enable_wasmtime; const enable_darling: bool = build_options.enable_darling; const enable_rosetta: bool = build_options.enable_rosetta; const glibc_runtimes_dir: ?[]const u8 = build_options.glibc_runtimes_dir; -const skip_stage1 = builtin.zig_backend != .stage1 or build_options.skip_stage1; +const skip_stage1 = true; const hr = "=" ** 80; test { - if (build_options.have_stage1) { - @import("stage1.zig").os_init(); - } - const use_gpa = build_options.force_gpa or !builtin.link_libc; const gpa = gpa: { if (use_gpa) { From fdb98c5ce121e80582aee9854bbe2543af725a74 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 03:14:54 -0500 Subject: [PATCH 38/68] cmake: fix stack size linker argument on mac --- CMakeLists.txt | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d2e9d89e61a..956a44482ab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -708,21 +708,6 @@ target_link_libraries(zigcpp LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} ) -if(MSVC) - set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2") - set(ZIG1_COMPILE_FLAGS "/std:c99 /Os") - set(ZIG2_COMPILE_FLAGS "/std:c99 /O0") - set(ZIG2_LINK_FLAGS "/STACK:16777216") -else() - set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") - set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -fbracket-depth=512") - endif() - set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") -endif() - if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") set(HOST_TARGET_ARCH "x86_64") elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") @@ -737,6 +722,25 @@ else() endif() set(HOST_TARGET_TRIPLE "${HOST_TARGET_ARCH}-${HOST_TARGET_OS}") +if(MSVC) + set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2") + set(ZIG1_COMPILE_FLAGS "/std:c99 /Os") + set(ZIG2_COMPILE_FLAGS "/std:c99 /O0") + set(ZIG2_LINK_FLAGS "/STACK:16777216") +else() + set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") + set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -fbracket-depth=512") + endif() + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") + else() + set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") + endif() +endif() + set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c") set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") From 9f4ef4de23927f724413efa6ef54c2cd08a05976 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 03:44:35 -0500 Subject: [PATCH 39/68] wasm2c: remove unnecessary brackets to reduce max bracket depth This avoids the need to pass `-fbracket-depth=512` to clang. --- CMakeLists.txt | 3 --- stage1/FuncGen.h | 20 +++++++++++++++----- stage1/wasm2c.c | 20 ++++++++++++++------ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 956a44482ab0..f08e95bae913 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -731,9 +731,6 @@ else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -fbracket-depth=512") - endif() if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") else() diff --git a/stage1/FuncGen.h b/stage1/FuncGen.h index 11bd4198f0dd..41717c3d4992 100644 --- a/stage1/FuncGen.h +++ b/stage1/FuncGen.h @@ -119,9 +119,15 @@ static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode if (self->block == NULL) panic("out of memory"); } uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind); - FuncGen_indent(self, out); - if (kind == WasmOpcode_if) fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(self)); - fputs("{\n", out); + + if (kind == WasmOpcode_if) { + FuncGen_indent(self, out); + fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(self)); + } else if (EXTRA_BRACES) { + FuncGen_indent(self, out); + fputs("{\n", out); + } + self->block[self->block_i].type = type < 0 ? ~type : type; self->block[self->block_i].label = label; self->block[self->block_i].stack_i = self->stack_i; @@ -148,8 +154,12 @@ static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) { uint32_t label = FuncGen_blockLabel(self, 0); if (kind != WasmOpcode_loop) FuncGen_label(self, out, label); self->block_i -= 1; - FuncGen_indent(self, out); - fputs("}\n", out); + + if (EXTRA_BRACES || kind == WasmOpcode_if) { + FuncGen_indent(self, out); + fputs("}\n", out); + } + if (self->stack_i != self->block[self->block_i].stack_i) { FuncGen_indent(self, out); fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i); diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c index 30258bd73613..26705a51d324 100644 --- a/stage1/wasm2c.c +++ b/stage1/wasm2c.c @@ -1,3 +1,5 @@ +#define EXTRA_BRACES 0 + #include "FuncGen.h" #include "InputStream.h" #include "panic.h" @@ -800,10 +802,14 @@ int main(int argc, char **argv) { FuncType_blockType(types, FuncGen_blockType(&fg, label_idx)); uint32_t label = FuncGen_blockLabel(&fg, label_idx); - FuncGen_indent(&fg, out); - if (opcode == WasmOpcode_br_if) - fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(&fg)); - fputs("{\n", out); + if (opcode == WasmOpcode_br_if) { + FuncGen_indent(&fg, out); + fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg)); + } else if (EXTRA_BRACES) { + FuncGen_indent(&fg, out); + fputs("{\n", out); + } + const struct ResultType *label_type; uint32_t lhs; switch (kind) { @@ -833,8 +839,10 @@ int main(int argc, char **argv) { } FuncGen_cont(&fg, out); fprintf(out, "goto l%" PRIu32 ";\n", label); - FuncGen_indent(&fg, out); - fprintf(out, "}\n"); + if (EXTRA_BRACES || opcode == WasmOpcode_br_if) { + FuncGen_indent(&fg, out); + fputs("}\n", out); + } if (opcode == WasmOpcode_br) unreachable_depth += 1; } break; From fad2142ecf2dcfe4b73f1707559dce7e8e9fce50 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 04:29:48 -0500 Subject: [PATCH 40/68] zig.h: fix shift ub for a shlo by 0 --- lib/zig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zig.h b/lib/zig.h index f827af1d5c4b..234ed707f7df 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -810,7 +810,7 @@ static inline void zig_vmulo_i16(zig_u8 *ov, zig_i16 *res, int n, \ static inline bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ - return (lhs & zig_maxInt_u##w << (bits - rhs)) != zig_as_u##w(0); \ + return lhs > zig_maxInt_u##w >> rhs; \ } \ \ static inline bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ @@ -1340,7 +1340,7 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { *res = zig_shlw_u128(lhs, rhs, bits); - return zig_and_u128(lhs, zig_shl_u128(zig_maxInt_u128, bits - rhs)) != zig_as_u128(0, 0); + return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt_u128, rhs)) > zig_as_i32(0); } static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { From c8541f0a12bcd07bfc24f565a58239cb5bde4c59 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 04:49:47 -0500 Subject: [PATCH 41/68] cc: remove argument parsing from only-c builds --- src/main.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.zig b/src/main.zig index c73e8acaf87b..1db5693e36e6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1406,6 +1406,8 @@ fn buildOutputType( } }, .cc, .cpp => { + if (build_options.only_c) unreachable; + emit_h = .no; soname = .no; ensure_libc_on_non_freestanding = true; From bd4a1f38fa6895e85dcec0436a779af75df1872a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 05:05:59 -0500 Subject: [PATCH 42/68] zig.h: fix shlo breakage on smaller bitwidths --- lib/zig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zig.h b/lib/zig.h index 234ed707f7df..a8fa948dc826 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -810,7 +810,7 @@ static inline void zig_vmulo_i16(zig_u8 *ov, zig_i16 *res, int n, \ static inline bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ - return lhs > zig_maxInt_u##w >> rhs; \ + return lhs > zig_maxInt(u##w, bits) >> rhs; \ } \ \ static inline bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ @@ -1340,7 +1340,7 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { *res = zig_shlw_u128(lhs, rhs, bits); - return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt_u128, rhs)) > zig_as_i32(0); + return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0); } static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { From ec1334d2d41c3e1ca57ad1c3a213d4cc8fc8dd5e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 13:17:07 -0700 Subject: [PATCH 43/68] CMake: remove --color on This flag makes CI servers print garbage to the terminal. I started implementing detection in wasi.c, but it would have destroyed the beautiful code that only touches the C stdlib, does not do any conditional compilation based on the operating system, or rely on any POSIX functions. So instead, let's just do without this flag to retain simplicity in this step of the build process. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f08e95bae913..7291ea59b956 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -770,7 +770,6 @@ set(BUILD_ZIG2_ARGS --name zig2 -femit-bin="${ZIG2_C_SOURCE}" --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end -target "${HOST_TARGET_TRIPLE}" - --color on ) add_custom_command( From 57995c210064e954913d1f4ee16f315e78aa1a46 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 13:36:45 -0700 Subject: [PATCH 44/68] translate-c: remove stage1 conditions from tests --- test/translate_c.zig | 458 ++++++++++++++++++++----------------------- 1 file changed, 218 insertions(+), 240 deletions(-) diff --git a/test/translate_c.zig b/test/translate_c.zig index 690b584d920d..4ecb6835f5a9 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -549,27 +549,25 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - if (builtin.zig_backend != .stage1) { - cases.add("function prototype translated as optional", - \\typedef void (*fnptr_ty)(void); - \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); - \\struct foo { - \\ __attribute__((cdecl)) void (*foo)(void); - \\ void (*bar)(void); - \\ fnptr_ty baz; - \\ fnptr_attr_ty qux; - \\}; - , &[_][]const u8{ - \\pub const fnptr_ty = ?*const fn () callconv(.C) void; - \\pub const fnptr_attr_ty = ?*const fn () callconv(.C) void; - \\pub const struct_foo = extern struct { - \\ foo: ?*const fn () callconv(.C) void, - \\ bar: ?*const fn () callconv(.C) void, - \\ baz: fnptr_ty, - \\ qux: fnptr_attr_ty, - \\}; - }); - } + cases.add("function prototype translated as optional", + \\typedef void (*fnptr_ty)(void); + \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); + \\struct foo { + \\ __attribute__((cdecl)) void (*foo)(void); + \\ void (*bar)(void); + \\ fnptr_ty baz; + \\ fnptr_attr_ty qux; + \\}; + , &[_][]const u8{ + \\pub const fnptr_ty = ?*const fn () callconv(.C) void; + \\pub const fnptr_attr_ty = ?*const fn () callconv(.C) void; + \\pub const struct_foo = extern struct { + \\ foo: ?*const fn () callconv(.C) void, + \\ bar: ?*const fn () callconv(.C) void, + \\ baz: fnptr_ty, + \\ qux: fnptr_attr_ty, + \\}; + }); cases.add("function prototype with parenthesis", \\void (f0) (void *L); @@ -897,22 +895,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const baz = c_int; }); - if (builtin.zig_backend != .stage1) { - cases.add("casting pointers to ints and ints to pointers", - \\void foo(void); - \\void bar(void) { - \\ void *func_ptr = foo; - \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; - \\} - , &[_][]const u8{ - \\pub extern fn foo() void; - \\pub export fn bar() void { - \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo); - \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr))); - \\ _ = @TypeOf(typed_func_ptr); - \\} - }); - } + cases.add("casting pointers to ints and ints to pointers", + \\void foo(void); + \\void bar(void) { + \\ void *func_ptr = foo; + \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; + \\} + , &[_][]const u8{ + \\pub extern fn foo() void; + \\pub export fn bar() void { + \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo); + \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr))); + \\ _ = @TypeOf(typed_func_ptr); + \\} + }); cases.add("noreturn attribute", \\void foo(void) __attribute__((noreturn)); @@ -972,21 +968,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("typedef of function in struct field", - \\typedef void lws_callback_function(void); - \\struct Foo { - \\ void (*func)(void); - \\ lws_callback_function *callback_http; - \\}; - , &[_][]const u8{ - \\pub const lws_callback_function = fn () callconv(.C) void; - \\pub const struct_Foo = extern struct { - \\ func: ?*const fn () callconv(.C) void, - \\ callback_http: ?*const lws_callback_function, - \\}; - }); - } + cases.add("typedef of function in struct field", + \\typedef void lws_callback_function(void); + \\struct Foo { + \\ void (*func)(void); + \\ lws_callback_function *callback_http; + \\}; + , &[_][]const u8{ + \\pub const lws_callback_function = fn () callconv(.C) void; + \\pub const struct_Foo = extern struct { + \\ func: ?*const fn () callconv(.C) void, + \\ callback_http: ?*const lws_callback_function, + \\}; + }); cases.add("pointer to struct demoted to opaque due to bit fields", \\struct Foo { @@ -1057,19 +1051,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - if (builtin.zig_backend != .stage1) { - cases.add("self referential struct with function pointer", - \\struct Foo { - \\ void (*derp)(struct Foo *foo); - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ derp: ?*const fn ([*c]struct_Foo) callconv(.C) void, - \\}; - , - \\pub const Foo = struct_Foo; - }); - } + cases.add("self referential struct with function pointer", + \\struct Foo { + \\ void (*derp)(struct Foo *foo); + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ derp: ?*const fn ([*c]struct_Foo) callconv(.C) void, + \\}; + , + \\pub const Foo = struct_Foo; + }); cases.add("struct prototype used in func", \\struct Foo; @@ -1335,13 +1327,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn func(array: [*c]c_int) void; }); - if (builtin.zig_backend != .stage1) { - cases.add("__cdecl doesn't mess up function pointers", - \\void foo(void (__cdecl *fn_ptr)(void)); - , &[_][]const u8{ - \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.C) void) void; - }); - } + cases.add("__cdecl doesn't mess up function pointers", + \\void foo(void (__cdecl *fn_ptr)(void)); + , &[_][]const u8{ + \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.C) void) void; + }); cases.add("void cast", \\void foo() { @@ -1764,15 +1754,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern var my_enum: enum_enum_ty; }); - if (builtin.zig_backend != .stage1) { - cases.add("Parameterless function pointers", - \\typedef void (*fn0)(); - \\typedef void (*fn1)(char); - , &[_][]const u8{ - \\pub const fn0 = ?*const fn (...) callconv(.C) void; - \\pub const fn1 = ?*const fn (u8) callconv(.C) void; - }); - } + cases.add("Parameterless function pointers", + \\typedef void (*fn0)(); + \\typedef void (*fn1)(char); + , &[_][]const u8{ + \\pub const fn0 = ?*const fn (...) callconv(.C) void; + \\pub const fn1 = ?*const fn (u8) callconv(.C) void; + }); cases.addWithTarget("Calling convention", .{ .cpu_arch = .x86, @@ -1972,64 +1960,60 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); }); - if (builtin.zig_backend != .stage1) { - cases.add("generate inline func for #define global extern fn", - \\extern void (*fn_ptr)(void); - \\#define foo fn_ptr - \\ - \\extern char (*fn_ptr2)(int, float); - \\#define bar fn_ptr2 - , &[_][]const u8{ - \\pub extern var fn_ptr: ?*const fn () callconv(.C) void; - , - \\pub inline fn foo() void { - \\ return fn_ptr.?(); - \\} - , - \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.C) u8; - , - \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { - \\ return fn_ptr2.?(arg_1, arg_2); - \\} - }); - } + cases.add("generate inline func for #define global extern fn", + \\extern void (*fn_ptr)(void); + \\#define foo fn_ptr + \\ + \\extern char (*fn_ptr2)(int, float); + \\#define bar fn_ptr2 + , &[_][]const u8{ + \\pub extern var fn_ptr: ?*const fn () callconv(.C) void; + , + \\pub inline fn foo() void { + \\ return fn_ptr.?(); + \\} + , + \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.C) u8; + , + \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { + \\ return fn_ptr2.?(arg_1, arg_2); + \\} + }); - if (builtin.zig_backend != .stage1) { - cases.add("macros with field targets", - \\typedef unsigned int GLbitfield; - \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); - \\typedef void(*OpenGLProc)(void); - \\union OpenGLProcs { - \\ OpenGLProc ptr[1]; - \\ struct { - \\ PFNGLCLEARPROC Clear; - \\ } gl; - \\}; - \\extern union OpenGLProcs glProcs; - \\#define glClearUnion glProcs.gl.Clear - \\#define glClearPFN PFNGLCLEARPROC - , &[_][]const u8{ - \\pub const GLbitfield = c_uint; - \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.C) void; - \\pub const OpenGLProc = ?*const fn () callconv(.C) void; - \\const struct_unnamed_1 = extern struct { - \\ Clear: PFNGLCLEARPROC, - \\}; - \\pub const union_OpenGLProcs = extern union { - \\ ptr: [1]OpenGLProc, - \\ gl: struct_unnamed_1, - \\}; - \\pub extern var glProcs: union_OpenGLProcs; - , - \\pub const glClearPFN = PFNGLCLEARPROC; - , - \\pub inline fn glClearUnion(arg_2: GLbitfield) void { - \\ return glProcs.gl.Clear.?(arg_2); - \\} - , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - } + cases.add("macros with field targets", + \\typedef unsigned int GLbitfield; + \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); + \\typedef void(*OpenGLProc)(void); + \\union OpenGLProcs { + \\ OpenGLProc ptr[1]; + \\ struct { + \\ PFNGLCLEARPROC Clear; + \\ } gl; + \\}; + \\extern union OpenGLProcs glProcs; + \\#define glClearUnion glProcs.gl.Clear + \\#define glClearPFN PFNGLCLEARPROC + , &[_][]const u8{ + \\pub const GLbitfield = c_uint; + \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.C) void; + \\pub const OpenGLProc = ?*const fn () callconv(.C) void; + \\const struct_unnamed_1 = extern struct { + \\ Clear: PFNGLCLEARPROC, + \\}; + \\pub const union_OpenGLProcs = extern union { + \\ ptr: [1]OpenGLProc, + \\ gl: struct_unnamed_1, + \\}; + \\pub extern var glProcs: union_OpenGLProcs; + , + \\pub const glClearPFN = PFNGLCLEARPROC; + , + \\pub inline fn glClearUnion(arg_2: GLbitfield) void { + \\ return glProcs.gl.Clear.?(arg_2); + \\} + , + \\pub const OpenGLProcs = union_OpenGLProcs; + }); cases.add("macro pointer cast", \\#define NRF_GPIO_BASE 0 @@ -2936,37 +2920,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("deref function pointer", - \\void foo(void) {} - \\int baz(void) { return 0; } - \\void bar(void) { - \\ void(*f)(void) = foo; - \\ int(*b)(void) = baz; - \\ f(); - \\ (*(f))(); - \\ foo(); - \\ b(); - \\ (*(b))(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub export fn baz() c_int { - \\ return 0; - \\} - \\pub export fn bar() void { - \\ var f: ?*const fn () callconv(.C) void = &foo; - \\ var b: ?*const fn () callconv(.C) c_int = &baz; - \\ f.?(); - \\ f.?(); - \\ foo(); - \\ _ = b.?(); - \\ _ = b.?(); - \\ _ = baz(); - \\} - }); - } + cases.add("deref function pointer", + \\void foo(void) {} + \\int baz(void) { return 0; } + \\void bar(void) { + \\ void(*f)(void) = foo; + \\ int(*b)(void) = baz; + \\ f(); + \\ (*(f))(); + \\ foo(); + \\ b(); + \\ (*(b))(); + \\ baz(); + \\} + , &[_][]const u8{ + \\pub export fn foo() void {} + \\pub export fn baz() c_int { + \\ return 0; + \\} + \\pub export fn bar() void { + \\ var f: ?*const fn () callconv(.C) void = &foo; + \\ var b: ?*const fn () callconv(.C) c_int = &baz; + \\ f.?(); + \\ f.?(); + \\ foo(); + \\ _ = b.?(); + \\ _ = b.?(); + \\ _ = baz(); + \\} + }); cases.add("pre increment/decrement", \\void foo(void) { @@ -3241,77 +3223,73 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("implicit casts", - \\#include - \\ - \\void fn_int(int x); - \\void fn_f32(float x); - \\void fn_f64(double x); - \\void fn_char(char x); - \\void fn_bool(bool x); - \\void fn_ptr(void *x); - \\ - \\void call() { - \\ fn_int(3.0f); - \\ fn_int(3.0); - \\ fn_int('ABCD'); - \\ fn_f32(3); - \\ fn_f64(3); - \\ fn_char('3'); - \\ fn_char('\x1'); - \\ fn_char(0); - \\ fn_f32(3.0f); - \\ fn_f64(3.0); - \\ fn_bool(123); - \\ fn_bool(0); - \\ fn_bool(&fn_int); - \\ fn_int((int)&fn_int); - \\ fn_ptr((void *)42); - \\} - , &[_][]const u8{ - \\pub extern fn fn_int(x: c_int) void; - \\pub extern fn fn_f32(x: f32) void; - \\pub extern fn fn_f64(x: f64) void; - \\pub extern fn fn_char(x: u8) void; - \\pub extern fn fn_bool(x: bool) void; - \\pub extern fn fn_ptr(x: ?*anyopaque) void; - \\pub export fn call() void { - \\ fn_int(@floatToInt(c_int, 3.0)); - \\ fn_int(@floatToInt(c_int, 3.0)); - \\ fn_int(@as(c_int, 1094861636)); - \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); - \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3')))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01')))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0)))); - \\ fn_f32(3.0); - \\ fn_f64(3.0); - \\ fn_bool(@as(c_int, 123) != 0); - \\ fn_bool(@as(c_int, 0) != 0); - \\ fn_bool(@ptrToInt(&fn_int) != 0); - \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); - \\ fn_ptr(@intToPtr(?*anyopaque, @as(c_int, 42))); - \\} - }); - } - - if (builtin.zig_backend != .stage1) { - cases.add("function call", - \\static void bar(void) { } - \\void foo(int *(baz)(void)) { - \\ bar(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub fn bar() callconv(.C) void {} - \\pub export fn foo(arg_baz: ?*const fn () callconv(.C) [*c]c_int) void { - \\ var baz = arg_baz; - \\ bar(); - \\ _ = baz.?(); - \\} - }); - } + cases.add("implicit casts", + \\#include + \\ + \\void fn_int(int x); + \\void fn_f32(float x); + \\void fn_f64(double x); + \\void fn_char(char x); + \\void fn_bool(bool x); + \\void fn_ptr(void *x); + \\ + \\void call() { + \\ fn_int(3.0f); + \\ fn_int(3.0); + \\ fn_int('ABCD'); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_char('3'); + \\ fn_char('\x1'); + \\ fn_char(0); + \\ fn_f32(3.0f); + \\ fn_f64(3.0); + \\ fn_bool(123); + \\ fn_bool(0); + \\ fn_bool(&fn_int); + \\ fn_int((int)&fn_int); + \\ fn_ptr((void *)42); + \\} + , &[_][]const u8{ + \\pub extern fn fn_int(x: c_int) void; + \\pub extern fn fn_f32(x: f32) void; + \\pub extern fn fn_f64(x: f64) void; + \\pub extern fn fn_char(x: u8) void; + \\pub extern fn fn_bool(x: bool) void; + \\pub extern fn fn_ptr(x: ?*anyopaque) void; + \\pub export fn call() void { + \\ fn_int(@floatToInt(c_int, 3.0)); + \\ fn_int(@floatToInt(c_int, 3.0)); + \\ fn_int(@as(c_int, 1094861636)); + \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); + \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0)))); + \\ fn_f32(3.0); + \\ fn_f64(3.0); + \\ fn_bool(@as(c_int, 123) != 0); + \\ fn_bool(@as(c_int, 0) != 0); + \\ fn_bool(@ptrToInt(&fn_int) != 0); + \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); + \\ fn_ptr(@intToPtr(?*anyopaque, @as(c_int, 42))); + \\} + }); + + cases.add("function call", + \\static void bar(void) { } + \\void foo(int *(baz)(void)) { + \\ bar(); + \\ baz(); + \\} + , &[_][]const u8{ + \\pub fn bar() callconv(.C) void {} + \\pub export fn foo(arg_baz: ?*const fn () callconv(.C) [*c]c_int) void { + \\ var baz = arg_baz; + \\ bar(); + \\ _ = baz.?(); + \\} + }); cases.add("macro defines string literal with octal", \\#define FOO "aoeu\023 derp" From cb012490eeae618b42361990872b9001e5672be1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 14:05:40 -0700 Subject: [PATCH 45/68] translate-c: fix wrong logic adjustment In ea9ad1e85dd5e2ba18e7d55f7a7f9694282159f1, I incorrectly applied boolean logic to one of the pieces of logic, resulting in a regression in translate-c. --- src/translate_c/ast.zig | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 00f5481b9878..1ed2eb568c63 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -1434,12 +1434,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"), .address_of => { const payload = node.castTag(.address_of).?.data; - if (payload.tag() == .fn_identifier) - return try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), - .data = undefined, - }); const ampersand = try c.addToken(.ampersand, "&"); const base = if (payload.tag() == .fn_identifier) From e73170f9725c530befc688dd40053022072f5058 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 15:52:44 -0700 Subject: [PATCH 46/68] std: fix WASI regressions This branch largely reverts 58f961f4cb9875bbce3070969438ecf08f392c9f. I would like to revisit the proposal to modify the standard library in this way and think more carefully about it before adding isAbsolute() checks everywhere. --- lib/std/fs.zig | 23 ++++++++--------------- lib/std/fs/test.zig | 20 +++++--------------- lib/std/os.zig | 3 ++- lib/std/os/test.zig | 30 ++++++++++-------------------- lib/std/os/wasi.zig | 8 +++++++- 5 files changed, 32 insertions(+), 52 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 2640abff1e8e..e253aaff9e95 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1488,19 +1488,7 @@ pub const Dir = struct { /// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`. pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) ![]u8 { if (builtin.os.tag == .wasi) { - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(pathname)) { - var buffer: [MAX_PATH_BYTES]u8 = undefined; - const out_path = try os.realpath(pathname, &buffer); - if (out_path.len > out_buffer.len) { - return error.NameTooLong; - } - mem.copy(u8, out_buffer, out_path); - return out_buffer[0..out_path.len]; - } else { - // Unfortunately, we have no ability to look up the path for an fd_t - // on WASI, so we have to give up here. - return error.InvalidHandle; - } + @compileError("realpath is not available on WASI"); } if (builtin.os.tag == .windows) { const pathname_w = try os.windows.sliceToPrefixedFileW(pathname); @@ -2652,8 +2640,13 @@ pub const Dir = struct { pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; - } else if (builtin.os.tag == .wasi and @hasDecl(root, "wasi_cwd")) { - return root.wasi_cwd(); + } else if (builtin.os.tag == .wasi) { + if (@hasDecl(root, "wasi_cwd")) { + return root.wasi_cwd(); + } else { + // Expect the first preopen to be current working directory. + return .{ .fd = 3 }; + } } else { return Dir{ .fd = os.AT.FDCWD }; } diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 556f3b845961..c497e213bf72 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -48,8 +48,7 @@ fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !vo } test "accessAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -67,8 +66,7 @@ test "accessAbsolute" { } test "openDirAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -104,8 +102,7 @@ test "openDir cwd parent .." { } test "readLinkAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -187,8 +184,6 @@ test "Dir.Iterator" { } test "Dir.Iterator many entries" { - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); - var tmp_dir = tmpIterableDir(.{}); defer tmp_dir.cleanup(); @@ -638,8 +633,7 @@ test "rename" { } test "renameAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp_dir = tmpDir(.{}); defer tmp_dir.cleanup(); @@ -1149,7 +1143,6 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { test "walker" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1203,7 +1196,6 @@ test "walker" { test "walker without fully iterating" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1227,7 +1219,6 @@ test "walker without fully iterating" { test ". and .. in fs.Dir functions" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1255,8 +1246,7 @@ test ". and .. in fs.Dir functions" { } test ". and .. in absolute functions" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/os.zig b/lib/std/os.zig index ab43b3a0a17e..fc021be954e3 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2032,7 +2032,7 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin if (builtin.os.tag == .windows) { @compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - return symlink(mem.sliceTo(target_path, 0), mem.sliceTo(sym_link_path, 0)); + return symlinkatZ(target_path, fs.cwd().fd, sym_link_path); } switch (errno(system.symlink(target_path, sym_link_path))) { .SUCCESS => return, @@ -2078,6 +2078,7 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c .SUCCESS => {}, .FAULT => unreachable, .INVAL => unreachable, + .BADF => unreachable, .ACCES => return error.AccessDenied, .PERM => return error.AccessDenied, .DQUOT => return error.DiskQuota, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index ed86024dcdac..44d0e0c80891 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -22,8 +22,7 @@ const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; test "chdir smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd"); + if (native_os == .wasi) return error.SkipZigTest; // Get current working directory path var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; @@ -75,8 +74,7 @@ test "chdir smoke test" { } test "open smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; // TODO verify file attributes using `fstat` @@ -131,7 +129,6 @@ test "open smoke test" { test "openat smoke test" { if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); // TODO verify file attributes using `fstatat` @@ -168,7 +165,6 @@ test "openat smoke test" { test "symlink with relative paths" { if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); const cwd = fs.cwd(); cwd.deleteFile("file.txt") catch {}; @@ -219,15 +215,10 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { } test "link with relative paths" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => { - if (builtin.link_libc) { - return error.SkipZigTest; - } else { - try os.initPreopensWasi(std.heap.page_allocator, "/"); - } - }, - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -263,9 +254,10 @@ test "link with relative paths" { } test "linkat with different directories" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => if (!builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"), - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -950,8 +942,7 @@ test "POSIX file locking with fcntl" { } test "rename smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1007,8 +998,7 @@ test "rename smoke test" { } test "access smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 308b6cc23dea..711352e2fe20 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,6 +1,7 @@ // wasi_snapshot_preview1 spec available (in witx format) here: // * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx // * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx +const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; @@ -157,7 +158,12 @@ pub const IOV_MAX = 1024; pub const AT = struct { pub const REMOVEDIR: u32 = 0x4; - pub const FDCWD: fd_t = -2; + /// When linking libc, we follow their convention and use -2 for current working directory. + /// However, without libc, Zig does a different convention: it assumes the + /// current working directory is the first preopen. This behavior can be + /// overridden with a public function called `wasi_cwd` in the root source + /// file. + pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3; }; // As defined in the wasi_snapshot_preview1 spec file: From aaf95ce849e7ae22a838aad5eac3dd5754a925cd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 15:54:07 -0700 Subject: [PATCH 47/68] CMake: adjust apple clang compiler check Before it was checking if the compiler was AppleClang, however, this did not handle the case when using a compiled-from-source Clang on a macOS computer, in which case the linker is still Apple ld64, and it is in fact the linker that needs to have the different flag to communicate stack size. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7291ea59b956..3f1a9ce43c67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -731,7 +731,7 @@ else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") - if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + if(APPLE) set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") else() set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") From a3fadd281309cd19924f4cd4007919a42cc5e1da Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 16:31:24 -0700 Subject: [PATCH 48/68] stage2: revert change to handling of --color on This change has been extracted to #13786 and can be solved separately than this branch. --- src/Compilation.zig | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 42b64f979f96..e3c45678e2b1 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2380,16 +2380,7 @@ pub fn update(comp: *Compilation) !void { var progress: std.Progress = .{ .dont_print_on_dumb = true }; const main_progress_node = progress.start("", 0); defer main_progress_node.end(); - switch (comp.color) { - .off => { - progress.terminal = null; - }, - .on => { - progress.terminal = std.io.getStdErr(); - progress.supports_ansi_escape_codes = true; - }, - .auto => {}, - } + if (comp.color == .off) progress.terminal = null; try comp.performAllTheWork(main_progress_node); From 5dbd28f17159e2750bba18a0b9204752bcf34c8f Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 17:55:45 -0500 Subject: [PATCH 49/68] wasm2c: support memory.copy with overlapping buffers --- stage1/wasm2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c index 26705a51d324..454e1cbed6ad 100644 --- a/stage1/wasm2c.c +++ b/stage1/wasm2c.c @@ -2377,7 +2377,7 @@ int main(int argc, char **argv) { uint32_t src = FuncGen_stackPop(&fg); uint32_t dst = FuncGen_stackPop(&fg); FuncGen_indent(&fg, out); - fprintf(out, "memcpy(&m%" PRIu32 "[l%" PRIu32 "], " + fprintf(out, "memmove(&m%" PRIu32 "[l%" PRIu32 "], " "&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n", dst_mem_idx, dst, src_mem_idx, src, n); } From 4a701490d4c403938e093c6bfb32b8723eb01786 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 17:55:47 -0500 Subject: [PATCH 50/68] zig.h: avoid using _Float16 when __builtin_inff16 isn't available --- lib/zig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zig.h b/lib/zig.h index a8fa948dc826..3f31fcff920f 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -1556,7 +1556,7 @@ typedef double zig_f16; #define zig_bitSizeOf_c_longdouble 16 typedef long double zig_f16; #define zig_as_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 +#elif FLT16_MANT_DIG == 11 && zig_has_builtin(__builtin_inff16) typedef _Float16 zig_f16; #define zig_as_f16(fp, repr) fp##f16 #elif defined(__SIZEOF_FP16__) From 823d1e70876d79dfae9dde0496e7cf293995c44a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 17:20:06 -0700 Subject: [PATCH 51/68] add std.heap.wasm_allocator --- lib/std/heap.zig | 10 ++++++++++ src/main.zig | 5 +---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/std/heap.zig b/lib/std/heap.zig index ac77db7a798f..ee6525659eae 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -224,6 +224,16 @@ else .vtable = &PageAllocator.vtable, }; +/// This allocator is fast, small, and specific to WebAssembly. In the future, +/// this will be the implementation automatically selected by +/// `GeneralPurposeAllocator` when compiling in `ReleaseSmall` mode for wasm32 +/// and wasm64 architectures. +/// Until then, it is available here to play with. +pub const wasm_allocator = Allocator{ + .ptr = undefined, + .vtable = &std.heap.WasmAllocator.vtable, +}; + /// Verifies that the adjusted length will still map to the full length pub fn alignPageAllocLen(full_len: usize, len: usize) usize { const aligned_len = mem.alignAllocLen(full_len, len); diff --git a/src/main.zig b/src/main.zig index 1db5693e36e6..67b67fa923c4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -155,10 +155,7 @@ pub fn main() anyerror!void { const use_gpa = (build_options.force_gpa or !builtin.link_libc) and builtin.os.tag != .wasi; const gpa = gpa: { if (builtin.os.tag == .wasi) { - break :gpa Allocator{ - .ptr = undefined, - .vtable = &std.heap.WasmAllocator.vtable, - }; + break :gpa std.heap.wasm_allocator; } if (use_gpa) { break :gpa general_purpose_allocator.allocator(); From 4451786c664ff4c0af11d76889b3f4f580134b38 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 17:21:33 -0700 Subject: [PATCH 52/68] langref: update WASI preopens example --- doc/langref.html.in | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index bf2a6fd71d6c..b2e408dda774 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -10961,24 +10961,28 @@ pub fn main() !void { {#code_begin|exe|preopens#} {#target_wasi#} const std = @import("std"); -const PreopenList = std.fs.wasi.PreopenList; +const fs = std.fs; pub fn main() !void { var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; const gpa = general_purpose_allocator.allocator(); - var preopens = PreopenList.init(gpa); - defer preopens.deinit(); + var arena_instance = std.heap.ArenaAllocator.init(gpa); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); - try preopens.populate(null); + const preopens = try fs.wasi.preopensAlloc(arena); - for (preopens.asSlice()) |preopen, i| { - std.debug.print("{}: {}\n", .{ i, preopen }); + for (preopens.names) |preopen, i| { + std.debug.print("{}: {s}\n", .{ i, preopen }); } } {#code_end#} {#shell_samp#}$ wasmtime --dir=. preopens.wasm -0: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } } +0: stdin +1: stdout +2: stderr +3: . {#end_shell_samp#} {#header_close#} {#header_close#} From ee2fb5b2ab4b950baca814e7339ced10f618ca35 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 17:21:39 -0700 Subject: [PATCH 53/68] zig.h: fix f16 has builtin check --- lib/zig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zig.h b/lib/zig.h index 3f31fcff920f..9fb01f8fbaa6 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -1556,7 +1556,7 @@ typedef double zig_f16; #define zig_bitSizeOf_c_longdouble 16 typedef long double zig_f16; #define zig_as_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && zig_has_builtin(__builtin_inff16) +#elif FLT16_MANT_DIG == 11 && zig_has_builtin(inff16) typedef _Float16 zig_f16; #define zig_as_f16(fp, repr) fp##f16 #elif defined(__SIZEOF_FP16__) From eef43489534476c98e7ea703e7c5c2e874e7100c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 17:33:56 -0700 Subject: [PATCH 54/68] CMake: remove --color on for compiler_rt too Missing change from bcd4ea9b28a7560a1c1ef28c6c7258c6126c80e5 --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f1a9ce43c67..0f0151894cf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -787,7 +787,6 @@ set(BUILD_COMPILER_RT_ARGS --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}" --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end -target "${HOST_TARGET_TRIPLE}" - --color on ) add_custom_command( From 3fb1b2caefd692aa351b5add4cbcbbf91e4e9f9f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 17:55:48 -0700 Subject: [PATCH 55/68] CI: use a patched tarball In the CI system, I copied the old tarball and then applied 05c21a26cb2d5daf06191bd996d0770192704b66 to its compiler_rt implementation. After this is verified we can drop this commit and regenerate the tarballs from a master branch commit. --- ci/aarch64-linux-debug.sh | 2 +- ci/aarch64-linux-release.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/aarch64-linux-debug.sh b/ci/aarch64-linux-debug.sh index b49c47967c98..2fc751b772f4 100644 --- a/ci/aarch64-linux-debug.sh +++ b/ci/aarch64-linux-debug.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e-1" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/aarch64-linux-release.sh b/ci/aarch64-linux-release.sh index 394361269d77..046d4c8f281e 100644 --- a/ci/aarch64-linux-release.sh +++ b/ci/aarch64-linux-release.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e-1" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" From 98338358ede66020458e83b1ec7cda79eac2698b Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 20:05:34 -0500 Subject: [PATCH 56/68] cmake: fix bootstrap dependencies --- CMakeLists.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f0151894cf0..e78849897938 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -738,7 +738,7 @@ else() endif() endif() -set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") +set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c") set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") @@ -750,9 +750,9 @@ target_compile_definitions(zig-wasm2c PRIVATE ZSTD_DISABLE_ASM) add_custom_command( OUTPUT "${ZIG1_C_SOURCE}" - COMMAND zig-wasm2c "${ZIG1_WASM_SOURCE}" "${ZIG1_C_SOURCE}" - DEPENDS zig-wasm2c "${ZIG1_WASM_SOURCE}" - COMMENT STATUS "Converting ${ZIG1_WASM_SOURCE} to ${ZIG1_C_SOURCE}" + COMMAND zig-wasm2c "${ZIG1_WASM_ZST_SOURCE}" "${ZIG1_C_SOURCE}" + DEPENDS zig-wasm2c "${ZIG1_WASM_ZST_SOURCE}" + COMMENT STATUS "Converting ${ZIG1_WASM_ZST_SOURCE} to ${ZIG1_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) @@ -762,20 +762,19 @@ target_link_libraries(zig1 LINK_PUBLIC m) target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) -set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") set(BUILD_ZIG2_ARGS "${CMAKE_SOURCE_DIR}/lib" build-exe src/main.zig -ofmt=c -lc -OReleaseSmall --name zig2 -femit-bin="${ZIG2_C_SOURCE}" - --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end -target "${HOST_TARGET_TRIPLE}" ) add_custom_command( OUTPUT "${ZIG2_C_SOURCE}" COMMAND zig1 ${BUILD_ZIG2_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" COMMENT STATUS "Running zig1.wasm to produce ${ZIG2_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) @@ -785,14 +784,14 @@ set(BUILD_COMPILER_RT_ARGS build-obj lib/compiler_rt.zig -ofmt=c -OReleaseSmall --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}" - --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end -target "${HOST_TARGET_TRIPLE}" ) add_custom_command( OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" "${ZIG1_WASM_ZST_SOURCE}" + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" COMMENT STATUS "Running zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) From 793db278050973e00d71d6789b8d439a7bbbcaa9 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 5 Dec 2022 21:06:33 -0500 Subject: [PATCH 57/68] wasi: add support for windows paths --- stage1/wasi.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/stage1/wasi.c b/stage1/wasi.c index c378fc3a20dc..911ce6e52053 100644 --- a/stage1/wasi.c +++ b/stage1/wasi.c @@ -237,7 +237,7 @@ int main(int argc, char **argv) { des[3].filetype = wasi_filetype_directory; des[3].guest_path = dupe("/lib", sizeof("/lib")); - des[3].host_path = dupe(argv[1], strlen(argv[1])); + des[3].host_path = dupe(argv[1], strlen(argv[1]) + 1); fd_len = 6; fds = calloc(sizeof(struct FileDescriptor), fd_len); @@ -252,8 +252,27 @@ int main(int argc, char **argv) { wasm__start(); } +static bool isLetter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} +static bool isPathSep(char c) { + return c == '/' || c == '\\'; +} +static bool isAbsPath(const char *path, uint32_t path_len) { + if (path_len >= 1 && isPathSep(path[0])) return true; + if (path_len >= 3 && isLetter(path[0]) && path[1] == ':' && isPathSep(path[2])) return true; + return false; +} +static bool isSamePath(const char *a, const char *b, uint32_t len) { + for (uint32_t i = 0; i < len; i += 1) { + if (isPathSep(a[i]) && isPathSep(b[i])) continue; + if (a[i] != b[i]) return false; + } + return true; +} + static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32_t path_len, enum wasi_filetype filetype, time_t tim, uint32_t *res_de) { - if (path[0] != '/') { + if (isAbsPath(path, path_len)) { if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf; if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir; } @@ -267,7 +286,7 @@ static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32 de->atim = tim; de->mtim = tim; de->ctim = tim; - if (path[0] == '/') { + if (isAbsPath(path, path_len)) { de->guest_path = malloc(path_len + 1); if (de->guest_path == NULL) return wasi_errno_nomem; memcpy(&de->guest_path[0], path, path_len); @@ -307,10 +326,10 @@ static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32 static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) { (void)flags; - if (path[0] == '/') { + if (isAbsPath(path, path_len)) { for (uint32_t de = 0; de < de_len; de += 1) { if (des[de].guest_path == NULL) continue; - if (memcmp(&des[de].guest_path[0], path, path_len) != 0) continue; + if (!isSamePath(&des[de].guest_path[0], path, path_len)) continue; if (des[de].guest_path[path_len] != '\0') continue; if (res_de != NULL) *res_de = de; return wasi_errno_success; @@ -323,9 +342,9 @@ static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const ch size_t dir_guest_path_len = strlen(dir_de->guest_path); for (uint32_t de = 0; de < de_len; de += 1) { if (des[de].guest_path == NULL) continue; - if (memcmp(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len) != 0) continue; - if (des[de].guest_path[dir_guest_path_len] != '/') continue; - if (memcmp(&des[de].guest_path[dir_guest_path_len + 1], path, path_len) != 0) continue; + if (!isSamePath(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len)) continue; + if (!isPathSep(des[de].guest_path[dir_guest_path_len])) continue; + if (!isSamePath(&des[de].guest_path[dir_guest_path_len + 1], path, path_len)) continue; if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue; if (res_de != NULL) *res_de = de; return wasi_errno_success; From f46567e6bf80c4f5b21608383bf99cca8a77c3b0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 21:00:01 -0700 Subject: [PATCH 58/68] CI: update tarballs In particular, these two changes are relevant: * zig cc: support -stack in addition to --stack for linker arg - Fixes stack overflow when running zig2 on aarch64-macos. * compiler_rt: avoid using weak aliases - Fixes duplicate symbol when linking zig2 on aarch64-linux. --- ci/aarch64-linux-debug.sh | 2 +- ci/aarch64-linux-release.sh | 2 +- ci/aarch64-macos.sh | 2 +- ci/x86_64-macos.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/aarch64-linux-debug.sh b/ci/aarch64-linux-debug.sh index 2fc751b772f4..05cdcdd0787a 100644 --- a/ci/aarch64-linux-debug.sh +++ b/ci/aarch64-linux-debug.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e-1" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/aarch64-linux-release.sh b/ci/aarch64-linux-release.sh index 046d4c8f281e..b74ce134501a 100644 --- a/ci/aarch64-linux-release.sh +++ b/ci/aarch64-linux-release.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e-1" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/aarch64-macos.sh b/ci/aarch64-macos.sh index c520dbbec237..390ca498ecd2 100755 --- a/ci/aarch64-macos.sh +++ b/ci/aarch64-macos.sh @@ -9,7 +9,7 @@ set -e ZIGDIR="$(pwd)" TARGET="$ARCH-macos-none" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/x86_64-macos.sh b/ci/x86_64-macos.sh index 15769e31dd16..f09121ccd0d1 100755 --- a/ci/x86_64-macos.sh +++ b/ci/x86_64-macos.sh @@ -9,7 +9,7 @@ set -e ZIGDIR="$(pwd)" TARGET="$ARCH-macos-none" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/$CACHE_BASENAME" JOBS="-j3" From 0f2a7d3b54c72a3750de110c047b24597b52c409 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 21:05:48 -0700 Subject: [PATCH 59/68] CI: don't pass -Denable-stage1 when building stage4 --- ci/x86_64-linux-release.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh index b1b5cc380d50..c87a3cb32b0f 100755 --- a/ci/x86_64-linux-release.sh +++ b/ci/x86_64-linux-release.sh @@ -75,7 +75,6 @@ stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-l stage3-release/bin/zig build \ --prefix stage4-release \ -Denable-llvm \ - -Denable-stage1 \ -Dno-lib \ -Drelease \ -Dstrip \ From c58ebfb1e17c071e2f05c8e047b8c0bb7d23497f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Dec 2022 22:20:47 -0700 Subject: [PATCH 60/68] CI: aarch64-macos tarball patch I messed up the spelling of '-stack_size' making it '-stack' instead. Will need to fix on master branch. But let's test this here before making another master branch commit. --- ci/aarch64-macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/aarch64-macos.sh b/ci/aarch64-macos.sh index 390ca498ecd2..337c2bfa8e70 100755 --- a/ci/aarch64-macos.sh +++ b/ci/aarch64-macos.sh @@ -9,7 +9,7 @@ set -e ZIGDIR="$(pwd)" TARGET="$ARCH-macos-none" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356-1" PREFIX="$HOME/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" From c4dc8515b6321828e1bfa404657f9a5f33aa1346 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 00:22:39 -0500 Subject: [PATCH 61/68] compiler_rt: don't use the llvm windows v2u64 abi with the C backend --- lib/compiler_rt/common.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 2d373031e5e8..f16ecf0e188a 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -20,7 +20,7 @@ pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); // Libcalls that involve u128 on Windows x86-64 are expected by LLVM to use the // calling convention of @Vector(2, u64), rather than what's standard. -pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64; +pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64 and @import("builtin").object_format != .c; /// This governs whether to use these symbol names for f16/f32 conversions /// rather than the standard names: From 3686787f6751867dc2bc64c4088b56e11d06fd03 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 00:37:36 -0500 Subject: [PATCH 62/68] CBE: add windows-specific reserved identifiers --- src/codegen/c.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index f32d53ef0d4c..677a227c6ccb 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -120,6 +120,7 @@ pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsC } const reserved_idents = std.ComptimeStringMap(void, .{ + // C language .{ "alignas", { @setEvalBranchQuota(4000); } }, @@ -215,14 +216,22 @@ const reserved_idents = std.ComptimeStringMap(void, .{ .{ "void", {} }, .{ "volatile", {} }, .{ "while ", {} }, + + // windows.h + .{ "max", {} }, + .{ "min", {} }, }); fn isReservedIdent(ident: []const u8) bool { - if (ident.len >= 2 and ident[0] == '_') { + if (ident.len >= 2 and ident[0] == '_') { // C language switch (ident[1]) { 'A'...'Z', '_' => return true, else => return false, } + } else if (std.mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or + std.mem.startsWith(u8, ident, "DUMMYUNIONNAME")) + { // windows.h + return true; } else return reserved_idents.has(ident); } From 3683602226f6675edae8c38e2a43b0626783267b Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 02:16:29 -0500 Subject: [PATCH 63/68] wasm2c: improve amortized speed of memory.grow --- stage1/wasm2c.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c index 454e1cbed6ad..3beba3b04427 100644 --- a/stage1/wasm2c.c +++ b/stage1/wasm2c.c @@ -91,7 +91,7 @@ int main(int argc, char **argv) { InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file"); if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version"); - FILE *out = fopen(argv[2], "w"); + FILE *out = fopen(argv[2], "wb"); if (out == NULL) panic("unable to open output file"); fputs("#include \n" "#include \n" @@ -225,14 +225,22 @@ int main(int argc, char **argv) { " return dst;\n" "}\n" "\n" - "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t n) {\n" + "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n" + " uint8_t *new_m = *m;\n" " uint32_t r = *p;\n" " uint32_t new_p = r + n;\n" - " uint8_t *new_m = realloc(*m, new_p << 16);\n" - " if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n" - " memset(&new_m[r << 16], 0, n << 16);\n" - " *m = new_m;\n" + " if (new_p > UINT32_C(0x10000)) return UINT32_C(0xFFFFFFF);\n" + " uint32_t new_c = *c;\n" + " if (new_c < new_p) {\n" + " do new_c += new_c / 2 + 8; while (new_c < new_p);\n" + " if (new_c > UINT32_C(0x10000)) new_c = UINT32_C(0x10000);\n" + " new_m = realloc(new_m, new_c << 16);\n" + " if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n" + " *m = new_m;\n" + " *c = new_c;\n" + " }\n" " *p = new_p;\n" + " memset(&new_m[r << 16], 0, n << 16);\n" " return r;\n" "}\n" "\n" @@ -369,7 +377,8 @@ int main(int argc, char **argv) { for (uint32_t i = 0; i < mems_len; i += 1) { mems[i].limits = InputStream_readLimits(&in); fprintf(out, "static uint8_t *m%" PRIu32 ";\n" - "static uint32_t p%" PRIu32 ";\n", i, i); + "static uint32_t p%" PRIu32 ";\n" + "static uint32_t c%" PRIu32 ";\n", i, i, i); } fputc('\n', out); } @@ -1319,8 +1328,8 @@ int main(int argc, char **argv) { if (unreachable_depth == 0) { uint32_t pages = FuncGen_stackPop(&fg); FuncGen_stackPush(&fg, out, WasmValType_i32); - fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", l%" PRIu32 ");\n", - mem_idx, mem_idx, pages); + fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", &c%" PRIu32 + ", l%" PRIu32 ");\n", mem_idx, mem_idx, mem_idx, pages); } break; } @@ -2449,8 +2458,9 @@ int main(int argc, char **argv) { fputs("static void init_data(void) {\n", out); for (uint32_t i = 0; i < mems_len; i += 1) fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n" - " m%" PRIu32 " = calloc(p%" PRIu32 ", UINT32_C(1) << 16);\n", - i, mems[i].limits.min, i, i); + " c%" PRIu32 " = p%" PRIu32 ";\n" + " m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n", + i, mems[i].limits.min, i, i, i, i); for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { uint32_t mem_idx; switch (InputStream_readLeb128_u32(&in)) { From 91e489174bc3f2ceb508f067a289ee1d9625bcb3 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 02:52:48 -0500 Subject: [PATCH 64/68] CBE: avoid trailing space --- src/codegen/c.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 677a227c6ccb..0c2822739c1e 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4434,8 +4434,9 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeByte(')'); } try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); - try writer.writeAll(": "); + try writer.writeByte(':'); } + try writer.writeByte(' '); if (case_i != last_case_i) { const old_value_map = f.value_map; From 2a3d9c321e95af5fea54321015fd4a579e0c4158 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 03:27:37 -0500 Subject: [PATCH 65/68] compiler_rt: remove stack probe functions from c builds --- lib/compiler_rt.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 3ffaf9f0e5dc..5cce3daf29e2 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -108,7 +108,6 @@ comptime { _ = @import("compiler_rt/sqrt.zig"); _ = @import("compiler_rt/tan.zig"); _ = @import("compiler_rt/trunc.zig"); - _ = @import("compiler_rt/stack_probe.zig"); _ = @import("compiler_rt/divti3.zig"); _ = @import("compiler_rt/modti3.zig"); _ = @import("compiler_rt/multi3.zig"); @@ -211,6 +210,7 @@ comptime { if (@import("builtin").object_format != .c) { _ = @import("compiler_rt/atomics.zig"); + _ = @import("compiler_rt/stack_probe.zig"); // macOS has these functions inside libSystem. if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { From a0a2e757730cdf8fa8fe3df6f155d0aae1303438 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 6 Dec 2022 03:52:29 -0500 Subject: [PATCH 66/68] cmake: disable stack protector for zig2 to avoid link errors on windows On windows we get: lld-link: error: undefined symbol: __stack_chk_fail >>> referenced by CMakeFiles/zig2.dir/zig2.c.obj:(main) >>> referenced by CMakeFiles/zig2.dir/zig2.c.obj:(main_main) >>> referenced by CMakeFiles/zig2.dir/zig2.c.obj:(log_scoped_28_default_29_err__anon_2764) >>> referenced 36192 more times lld-link: error: undefined symbol: __stack_chk_guard >>> referenced by CMakeFiles/zig2.dir/zig2.c.obj:(.refptr.__stack_chk_guard) >>> referenced by CMakeFiles/zig2.dir/compiler_rt.c.obj --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e78849897938..1c03faf1e911 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -730,7 +730,7 @@ if(MSVC) else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O0") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-stack-protector") if(APPLE) set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") else() From 106e9678937a662fec220367d5d57d04eb09b6b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 6 Dec 2022 12:19:24 -0700 Subject: [PATCH 67/68] CI: revert windows script to master branch version This commit chickens out and reverts 02456a32ad6fa672ea383b57a2b9f592b9e2b9ed, leaving it for a future enhancement. --- ci/x86_64-windows.ps1 | 58 +++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/ci/x86_64-windows.ps1 b/ci/x86_64-windows.ps1 index 641657b2c643..c5907b47b249 100644 --- a/ci/x86_64-windows.ps1 +++ b/ci/x86_64-windows.ps1 @@ -1,17 +1,20 @@ $TARGET = "$($Env:ARCH)-windows-gnu" $ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" -$MCPU = "baseline" $ZIG_LLVM_CLANG_LLD_URL = "https://ziglang.org/deps/$ZIG_LLVM_CLANG_LLD_NAME.zip" -$PREFIX_PATH = "$(Get-Location)\$ZIG_LLVM_CLANG_LLD_NAME" -$ZIG = "$PREFIX_PATH\bin\zig.exe" Write-Output "Downloading $ZIG_LLVM_CLANG_LLD_URL" + Invoke-WebRequest -Uri "$ZIG_LLVM_CLANG_LLD_URL" -OutFile "$ZIG_LLVM_CLANG_LLD_NAME.zip" Write-Output "Extracting..." + Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD/$ZIG_LLVM_CLANG_LLD_NAME.zip", "$PWD") +Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib" +Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release" +Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$ZIG_LLVM_CLANG_LLD_NAME" + function CheckLastExitCode { if (!$?) { exit 1 @@ -28,41 +31,32 @@ if ((git rev-parse --is-shallow-repository) -eq "true") { git fetch --unshallow # `git describe` won't work on a shallow repo } -Write-Output "Building from source..." -Remove-Item -Path 'build-release' -Recurse -Force -ErrorAction Ignore -New-Item -Path 'build-release' -ItemType Directory -Set-Location -Path 'build-release' +Write-Output "Building Zig..." -# CMake gives a syntax error when file paths with backward slashes are used. -# Here, we use forward slashes only to work around this. -& cmake .. ` - -GNinja ` - -DCMAKE_INSTALL_PREFIX="stage3-release" ` - -DCMAKE_PREFIX_PATH="$($PREFIX_PATH -Replace "\\", "/")" ` - -DCMAKE_BUILD_TYPE=Release ` - -DCMAKE_C_COMPILER="$($ZIG -Replace "\\", "/");cc;-target;$TARGET;-mcpu=$MCPU" ` - -DCMAKE_CXX_COMPILER="$($ZIG -Replace "\\", "/");c++;-target;$TARGET;-mcpu=$MCPU" ` - -DZIG_TARGET_TRIPLE="$TARGET" ` - -DZIG_TARGET_MCPU="$MCPU" ` - -DZIG_STATIC=ON +& "$ZIGPREFIXPATH\bin\zig.exe" build ` + --prefix "$ZIGINSTALLDIR" ` + --search-prefix "$ZIGPREFIXPATH" ` + --zig-lib-dir "$ZIGLIBDIR" ` + -Dstatic-llvm ` + -Drelease ` + -Duse-zig-libcxx ` + -Dtarget="$TARGET" CheckLastExitCode -ninja install -CheckLastExitCode +Write-Output " zig build test docs..." -Write-Output "Main test suite..." -& "stage3-release\bin\zig.exe" build test docs ` - --zig-lib-dir "..\lib" ` - --search-prefix "../$ZIG_LLVM_CLANG_LLD_NAME" ` - -Dstatic-llvm ` - -Dskip-non-native ` - -Denable-symlinks-windows +& "$ZIGINSTALLDIR\bin\zig.exe" build test docs ` + --search-prefix "$ZIGPREFIXPATH" ` + -Dstatic-llvm ` + -Dskip-non-native ` + -Denable-symlinks-windows CheckLastExitCode -Write-Output "Testing Autodocs..." -& "stage3-release\bin\zig.exe" test "..\lib\std\std.zig" ` - --zig-lib-dir "..\lib" ` +# Produce the experimental std lib documentation. +Write-Output "zig test std/std.zig..." + +& "$ZIGINSTALLDIR\bin\zig.exe" test "$ZIGLIBDIR\std\std.zig" ` + --zig-lib-dir "$ZIGLIBDIR" ` -femit-docs ` -fno-emit-bin CheckLastExitCode - From 20d86d9c63476b6312b87dc5b0e4aa4822eb7717 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 12 Nov 2022 16:35:20 -0700 Subject: [PATCH 68/68] add zig1.wasm.zst This commit adds a 637 KB binary file to the source repository. This commit does nothing else, so it should be replaced with a different commit before this branch is merged to avoid bloating the git repository. --- stage1/zig1.wasm.zst | Bin 0 -> 652012 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 stage1/zig1.wasm.zst diff --git a/stage1/zig1.wasm.zst b/stage1/zig1.wasm.zst new file mode 100644 index 0000000000000000000000000000000000000000..624745f3acd86cbd8f6f227a81ee968fca2e02bd GIT binary patch literal 652012 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

*i6l*0Rhuzj3}fsp;rH+HcAJ73?R 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

  • lH3t3K&r%%?_OGM=z%k^Mjl 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

    Tf6Y@}cLDkvmNj!&{cKp~MyCZ1g;z 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 OqAC*eSF9MaWDTqOYV0-u literal 0 HcmV?d00001