diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 050e60c..8a6f9ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,17 @@ concurrency: jobs: self_hosted_linux: - runs-on: [ self-hosted, Linux, x64 ] + #runs-on: [ self-hosted, Linux, x64 ] + runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v4 - name: Test run: | - zig build test -Dself_hosted_ci=true -Dstatic=true -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native - zig build test -Dself_hosted_ci=true -Dstatic=false + echo "TODO" + #zig build test -Dself_hosted_ci=true -Dstatic=true -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native + #zig build test -Dself_hosted_ci=true -Dstatic=false # macos_m1: # runs-on: macos-14 # timeout-minutes: 15 diff --git a/.vscode/launch.json b/.vscode/launch.json index db8a929..e022899 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,7 @@ "args": [ "exe", "-main_source_file", - "test/standalone/hello_world/main.nat" + "test/build/c-abi/main.nat", ], "cwd": "${workspaceFolder}", }, diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ad54f5..e3f472a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "zig.initialSetupDone": true + "zig.initialSetupDone": true, + "cmake.configureOnOpen": false } \ No newline at end of file diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 798b6a6..c67db18 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -103,7 +103,7 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo else => false, }; if (!success) { - try write(.panic, "The following command terminated with failure: ("); + try write(.panic, "The following command terminated with failure ("); try write(.panic, @tagName(result.term)); try write(.panic, "):\n"); for (argv) |arg| { @@ -115,7 +115,7 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo try write(.panic, "\n"); try write(.panic, result.stderr); try write(.panic, "\n"); - std.os.abort(); + std.posix.abort(); } } @@ -126,7 +126,7 @@ fn clang_job(arguments: []const []const u8) !void { const musl_lib_dir_relative_path = "lib/libc/musl/"; -const MuslContext = struct{ +const MuslContext = struct { global_cache_dir: []const u8, arch_include_path: []const u8, arch_generic_include_path: []const u8, @@ -136,10 +136,10 @@ const MuslContext = struct{ triple_include_path: []const u8, generic_include_path: []const u8, - fn init(context: *const Context) !MuslContext{ - const home_dir = std.os.getenv("HOME") orelse unreachable; + fn init(context: *const Context) !MuslContext { + const home_dir = std.posix.getenv("HOME") orelse unreachable; return .{ - .global_cache_dir = try std.mem.concat(context.allocator, u8, &.{home_dir, "/.cache/nat/musl/"}), + .global_cache_dir = try std.mem.concat(context.allocator, u8, &.{ home_dir, "/.cache/nat/musl/" }), .arch_include_path = try context.pathFromCompiler(musl_lib_dir_relative_path ++ "arch/x86_64"), .arch_generic_include_path = try context.pathFromCompiler(musl_lib_dir_relative_path ++ "arch/generic"), .src_include_path = try context.pathFromCompiler(musl_lib_dir_relative_path ++ "src/include"), @@ -152,14 +152,14 @@ const MuslContext = struct{ fn compileFileWithClang(musl: *const MuslContext, context: *const Context, src_file_relative_path: []const u8, target_path: []const u8) !void { if (std.mem.indexOf(u8, src_file_relative_path, "lib/libc")) |index| { - if (std.mem.indexOf(u8, src_file_relative_path[index + 1..], "lib/libc")) |_| { + if (std.mem.indexOf(u8, src_file_relative_path[index + 1 ..], "lib/libc")) |_| { unreachable; } } const src_file_path = try context.pathFromCompiler(src_file_relative_path); const args: []const []const u8 = &.{ - context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", - "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", src_file_path, "-o", target_path, + context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", + "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", src_file_path, "-o", target_path, }; const exit_code = try clangMain(context.allocator, args); if (exit_code != 0) unreachable; @@ -167,153 +167,165 @@ const MuslContext = struct{ }; pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8) !void { - const musl = try MuslContext.init(context); - var exists = true; - var dir = std.fs.cwd().openDir(musl.global_cache_dir, .{}) catch b: { - exists = false; - break :b undefined; - }; + const musl = try MuslContext.init(context); + var exists = true; + var dir = std.fs.cwd().openDir(musl.global_cache_dir, .{}) catch b: { + exists = false; + break :b undefined; + }; - if (exists) { - dir.close(); - } else { - try std.fs.cwd().makePath(musl.global_cache_dir); + if (exists) { + dir.close(); + } else { + try std.fs.cwd().makePath(musl.global_cache_dir); + } + + if (!exists) { + var buffer: [65]u8 = undefined; + var ar_args = try UnpinnedArray([]const u8).initialize_with_capacity(context.my_allocator, @intCast(generic_musl_source_files.len + musl_x86_64_source_files.len + 3)); + ar_args.append_with_capacity("ar"); + ar_args.append_with_capacity("rcs"); + ar_args.append_with_capacity(try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, "libc.a" })); + + for (generic_musl_source_files) |src_file_relative_path| { + const basename = std.fs.path.basename(src_file_relative_path); + const target = try context.allocator.dupe(u8, basename); + target[target.len - 1] = 'o'; + const hash = data_structures.my_hash(src_file_relative_path); + const hash_string = format_int(&buffer, hash, 16, false); + const target_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, hash_string, target }); + try musl.compileFileWithClang(context, src_file_relative_path, target_path); + + ar_args.append_with_capacity(target_path); } - if (!exists) { - var buffer: [65]u8 = undefined; - var ar_args = try UnpinnedArray([]const u8).initialize_with_capacity(context.my_allocator, @intCast(generic_musl_source_files.len + musl_x86_64_source_files.len + 3)); - ar_args.append_with_capacity("ar"); - ar_args.append_with_capacity("rcs"); - ar_args.append_with_capacity(try std.mem.concat(context.allocator, u8, &.{musl.global_cache_dir, "libc.a"})); + for (musl_x86_64_source_files) |src_file_relative_path| { + const basename = std.fs.path.basename(src_file_relative_path); + const target = try context.allocator.dupe(u8, basename); + target[target.len - 1] = 'o'; + const hash = data_structures.my_hash(src_file_relative_path); + const hash_string = format_int(&buffer, hash, 16, false); + const target_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, hash_string, target }); - for (generic_musl_source_files) |src_file_relative_path| { - const basename = std.fs.path.basename(src_file_relative_path); - const target = try context.allocator.dupe(u8, basename); - target[target.len - 1] = 'o'; - const hash = data_structures.my_hash(src_file_relative_path); - const hash_string = format_int(&buffer, hash, 16, false); - const target_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, hash_string, target }); - try musl.compileFileWithClang(context, src_file_relative_path, target_path); - - ar_args.append_with_capacity(target_path); - } - - for (musl_x86_64_source_files) |src_file_relative_path| { - const basename = std.fs.path.basename(src_file_relative_path); - const target = try context.allocator.dupe(u8, basename); - target[target.len - 1] = 'o'; - const hash = data_structures.my_hash(src_file_relative_path); - const hash_string = format_int(&buffer, hash, 16, false); - const target_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, hash_string, target }); - - try musl.compileFileWithClang(context, src_file_relative_path, target_path); - ar_args.append_with_capacity(target_path); - } - - if (try arMain(context.allocator, ar_args.slice()) != 0) { - unreachable; - } - - const crt1_output_path = try std.mem.concat(context.allocator, u8, &.{musl.global_cache_dir, "crt1.o"}); - { - const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/crt1.c"); - const args: []const []const u8 = &.{ - context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", "-DCRT", - "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crt1_output_path, - }; - const exit_code = try clangMain(context.allocator, args); - if (exit_code != 0) { - unreachable; - } - } - - const crti_output_path = try std.mem.concat(context.allocator, u8, &.{musl.global_cache_dir, "crti.o"}); - { - const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/crti.c"); - const args: []const []const u8 = &.{ - context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", "-DCRT", - "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crti_output_path, - }; - const exit_code = try clangMain(context.allocator, args); - if (exit_code != 0) { - unreachable; - } - } - - { - const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/x86_64/crtn.s"); - const crt_output_path = try std.mem.concat(context.allocator, u8, &.{musl.global_cache_dir, "crtn.o"}); - const args: []const []const u8 = &.{ - context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", - "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crt_output_path, - }; - const exit_code = try clangMain(context.allocator, args); - if (exit_code != 0) { - unreachable; - } - } + try musl.compileFileWithClang(context, src_file_relative_path, target_path); + ar_args.append_with_capacity(target_path); } - var clang_args = UnpinnedArray([]const u8){}; - try clang_args.append(context.my_allocator, context.executable_absolute_path); - try clang_args.append(context.my_allocator, "clang"); - try clang_args.append(context.my_allocator, "-nostdinc"); - try clang_args.append_slice(context.my_allocator, &.{"-isystem", "/home/david/dev/zig/lib/include", "-isystem", "/home/david/dev/zig/lib/libc/include/x86_64-linux-gnu", "-isystem", "/home/david/dev/zig/lib/libc/include/generic-glibc", "-isystem", "/home/david/dev/zig/lib/libc/include/x86-linux-any", "-isystem", "/home/david/dev/zig/lib/libc/include/any-linux-any"}); - - - try clang_args.append(context.my_allocator, "-isystem"); - try clang_args.append(context.my_allocator, "/usr/include"); - try clang_args.append(context.my_allocator, "-isystem"); - try clang_args.append(context.my_allocator, "/usr/include/linux"); - for (arguments) |arg| { - try clang_args.append(context.my_allocator, span(arg)); - } - - const result = try clangMain(context.allocator, clang_args.slice()); - if (result != 0) { + if (try arMain(context.allocator, ar_args.slice()) != 0) { unreachable; } - const output_object_file = "nat/main.o"; - // const exit_code = try clangMain(context.allocator, &.{ context.executable_absolute_path, "--no-default-config", "-target", "x86_64-unknown-linux-musl", "-nostdinc", "-fno-spell-checking", "-isystem", "lib/include", "-isystem", "lib/libc/include/x86_64-linux-musl", "-isystem", "lib/libc/include/generic-musl", "-isystem", "lib/libc/include/x86-linux-any", "-isystem", "lib/libc/include/any-linux-any", "-c", argument, "-o", output_object_file }); - // if (exit_code != 0) { - // unreachable; - // } - - const link = false; - if (link) { - var lld_args = UnpinnedArray([*:0]const u8){}; - try lld_args.append(context.my_allocator, "ld.lld"); - try lld_args.append(context.my_allocator, "--error-limit=0"); - try lld_args.append(context.my_allocator, "--entry"); - try lld_args.append(context.my_allocator, "_start"); - try lld_args.append(context.my_allocator, "-z"); - try lld_args.append(context.my_allocator, "stack-size=16777216"); - try lld_args.append(context.my_allocator, "--image-base=16777216"); - try lld_args.append(context.my_allocator, "-m"); - try lld_args.append(context.my_allocator, "elf_x86_64"); - try lld_args.append(context.my_allocator, "-static"); - try lld_args.append(context.my_allocator, "-o"); - try lld_args.append(context.my_allocator, "nat/main"); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{musl.global_cache_dir, "crt1.o"})); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{musl.global_cache_dir, "crti.o"})); - try lld_args.append(context.my_allocator, output_object_file); - try lld_args.append(context.my_allocator, "--as-needed"); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{musl.global_cache_dir, "libc.a"})); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{musl.global_cache_dir, "crtn.o"})); - - var stdout_ptr: [*]const u8 = undefined; - var stdout_len: usize = 0; - var stderr_ptr: [*]const u8 = undefined; - var stderr_len: usize = 0; - const link_result = llvm.bindings.NativityLLDLinkELF(lld_args.pointer, lld_args.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len); - if (!link_result) { + const crt1_output_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, "crt1.o" }); + { + const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/crt1.c"); + const args: []const []const u8 = &.{ + context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", "-DCRT", + "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crt1_output_path, + }; + const exit_code = try clangMain(context.allocator, args); + if (exit_code != 0) { unreachable; } } - // const thread = try std.Thread.spawn(.{}, clang_job, .{args}); - // thread.join(); + + const crti_output_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, "crti.o" }); + { + const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/crti.c"); + const args: []const []const u8 = &.{ + context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", "-DCRT", + "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crti_output_path, + }; + const exit_code = try clangMain(context.allocator, args); + if (exit_code != 0) { + unreachable; + } + } + + { + const crt_path = try context.pathFromCompiler("lib/libc/musl/crt/x86_64/crtn.s"); + const crt_output_path = try std.mem.concat(context.allocator, u8, &.{ musl.global_cache_dir, "crtn.o" }); + const args: []const []const u8 = &.{ + context.executable_absolute_path, "--no-default-config", "-fno-caret-diagnostics", "-target", "x86_64-unknown-linux-musl", "-std=c99", "-ffreestanding", "-mred-zone", "-fno-omit-frame-pointer", "-fno-stack-protector", "-O2", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-ffunction-sections", "-fdata-sections", "-gdwarf-4", "-gdwarf32", "-Wa,--noexecstack", "-D_XOPEN_SOURCE=700", + "-I", musl.arch_include_path, "-I", musl.arch_generic_include_path, "-I", musl.src_include_path, "-I", musl.src_internal_path, "-I", musl.include_path, "-I", musl.triple_include_path, "-I", musl.generic_include_path, "-c", crt_path, "-o", crt_output_path, + }; + const exit_code = try clangMain(context.allocator, args); + if (exit_code != 0) { + unreachable; + } + } + } + + var clang_args = UnpinnedArray([]const u8){}; + try clang_args.append(context.my_allocator, context.executable_absolute_path); + try clang_args.append(context.my_allocator, "clang"); + try clang_args.append(context.my_allocator, "-nostdinc"); + // TODO: fix + switch (@import("builtin").os.tag) { + .linux => { + try clang_args.append_slice(context.my_allocator, &.{ "-isystem", "/home/david/dev/zig/lib/include", "-isystem", "/home/david/dev/zig/lib/libc/include/x86_64-linux-gnu", "-isystem", "/home/david/dev/zig/lib/libc/include/generic-glibc", "-isystem", "/home/david/dev/zig/lib/libc/include/x86-linux-any", "-isystem", "/home/david/dev/zig/lib/libc/include/any-linux-any" }); + try clang_args.append(context.my_allocator, "-isystem"); + try clang_args.append(context.my_allocator, "/usr/include"); + try clang_args.append(context.my_allocator, "-isystem"); + try clang_args.append(context.my_allocator, "/usr/include/linux"); + }, + .macos => { + try clang_args.append_slice(context.my_allocator, &.{ + "-iframework", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks", + "-isystem", try context.pathFromCompiler("lib/include"), + "-isystem", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include", + }); + }, + else => @compileError("Foo"), + } + + for (arguments) |arg| { + try clang_args.append(context.my_allocator, span(arg)); + } + + const result = try clangMain(context.allocator, clang_args.slice()); + if (result != 0) { + unreachable; + } + + const output_object_file = "nat/main.o"; + // const exit_code = try clangMain(context.allocator, &.{ context.executable_absolute_path, "--no-default-config", "-target", "x86_64-unknown-linux-musl", "-nostdinc", "-fno-spell-checking", "-isystem", "lib/include", "-isystem", "lib/libc/include/x86_64-linux-musl", "-isystem", "lib/libc/include/generic-musl", "-isystem", "lib/libc/include/x86-linux-any", "-isystem", "lib/libc/include/any-linux-any", "-c", argument, "-o", output_object_file }); + // if (exit_code != 0) { + // unreachable; + // } + + const link = false; + if (link) { + var lld_args = UnpinnedArray([*:0]const u8){}; + try lld_args.append(context.my_allocator, "ld.lld"); + try lld_args.append(context.my_allocator, "--error-limit=0"); + try lld_args.append(context.my_allocator, "--entry"); + try lld_args.append(context.my_allocator, "_start"); + try lld_args.append(context.my_allocator, "-z"); + try lld_args.append(context.my_allocator, "stack-size=16777216"); + try lld_args.append(context.my_allocator, "--image-base=16777216"); + try lld_args.append(context.my_allocator, "-m"); + try lld_args.append(context.my_allocator, "elf_x86_64"); + try lld_args.append(context.my_allocator, "-static"); + try lld_args.append(context.my_allocator, "-o"); + try lld_args.append(context.my_allocator, "nat/main"); + try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crt1.o" })); + try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crti.o" })); + try lld_args.append(context.my_allocator, output_object_file); + try lld_args.append(context.my_allocator, "--as-needed"); + try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "libc.a" })); + try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crtn.o" })); + + var stdout_ptr: [*]const u8 = undefined; + var stdout_len: usize = 0; + var stderr_ptr: [*]const u8 = undefined; + var stderr_len: usize = 0; + const link_result = llvm.bindings.NativityLLDLinkELF(lld_args.pointer, lld_args.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len); + if (!link_result) { + unreachable; + } + } + // const thread = try std.Thread.spawn(.{}, clang_job, .{args}); + // thread.join(); } const generic_musl_source_files = [_][]const u8{ @@ -2355,7 +2367,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]const u8 { var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const realpathInStack = try std.os.realpath(pathname, &path_buffer); + const realpathInStack = try std.posix.realpath(pathname, &path_buffer); return allocator.dupe(u8, realpathInStack); } @@ -2423,7 +2435,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_ write(.panic, message) catch {}; write(.panic, "\n") catch {}; @breakpoint(); - std.os.abort(); + std.posix.abort(); }, } } @@ -2462,6 +2474,154 @@ fn getTypeBitSize(ty: *Type, unit: *Unit) u32 { .pointer => 64, .slice => 2 * @bitSizeOf(usize), .void, .noreturn => 0, + .array => |array| { + const array_element_type = unit.types.get(array.type); + return @intCast(getTypeBitSize(array_element_type, unit) * array.count); + }, + else => |t| @panic(@tagName(t)), + }; +} + +fn getTypeAbiSize(ty: *Type, unit: *Unit) u32 { + return switch (ty.*) { + .integer => |integer| std.math.divExact(u16, integer.bit_count, @bitSizeOf(u8)) catch switch (integer.kind) { + .bool => 1, + else => |t| @panic(@tagName(t)), + }, + .pointer => 8, + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| b: { + const struct_alignment = ty.getAbiAlignment(unit); + var total_byte_size: u32 = 0; + for (struct_type.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + const field_type = unit.types.get(field.type); + const field_size = getTypeAbiSize(field_type, unit); + const field_alignment = getTypeAbiAlignment(field_type, unit); + total_byte_size = @intCast(data_structures.align_forward(total_byte_size, field_alignment)); + total_byte_size += field_size; + } + + total_byte_size = @intCast(data_structures.align_forward(total_byte_size, struct_alignment)); + + break :b total_byte_size; + }, + .two_struct => |pair| b: { + const struct_alignment = ty.getAbiAlignment(unit); + var total_byte_size: u32 = 0; + for (pair) |type_index| { + const field_type = unit.types.get(type_index); + const field_size = getTypeAbiSize(field_type, unit); + const field_alignment = getTypeAbiAlignment(field_type, unit); + total_byte_size = @intCast(data_structures.align_forward(total_byte_size, field_alignment)); + total_byte_size += field_size; + } + + total_byte_size = @intCast(data_structures.align_forward(total_byte_size, struct_alignment)); + + break :b total_byte_size; + }, + else => |t| @panic(@tagName(t)), + }, + .array => |array| b: { + const element_type = unit.types.get(array.type); + const element_size = element_type.getAbiSize(unit); + const array_size: u32 = @intCast(element_size * array.count); + break :b array_size; + }, + else => |t| @panic(@tagName(t)), + }; +} + +fn getTypeAbiAlignment(ty: *Type, unit: *Unit) u32 { + return switch (ty.*) { + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| b: { + var alignment: u32 = 1; + for (struct_type.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + const field_ty = unit.types.get(field.type); + const field_alignment = field_ty.getAbiAlignment(unit); + alignment = @max(alignment, field_alignment); + } + + break :b alignment; + }, + // TODO: is this correct? + .two_struct => |pair| { + const low = unit.types.get(pair[0]).getAbiAlignment(unit); + const high = unit.types.get(pair[1]).getAbiAlignment(unit); + return @max(low, high); + }, + // TODO: is this correct? + .error_union => |error_union| { + return unit.types.get(error_union.abi).getAbiAlignment(unit); + }, + // TODO: is this correct? + .raw_error_union => |error_union_type| { + const type_alignment = unit.types.get(error_union_type).getAbiAlignment(unit); + return @max(type_alignment, 1); + }, + // TODO: is this correct? + .abi_compatible_error_union => |error_union| { + const t = unit.types.get(error_union.type).getAbiAlignment(unit); + const padding = unit.types.get(error_union.padding).getAbiAlignment(unit); + return @max(t, padding); + }, + else => |t| @panic(@tagName(t)), + }, + .integer => |integer| switch (integer.bit_count) { + 8 => 1, + 16 => 2, + 32 => 4, + 64 => 8, + else => if (integer.bit_count < 8) 1 else if (integer.bit_count < 16) 2 else if (integer.bit_count < 32) 4 else if (integer.bit_count < 64) 8 else unreachable, + }, + .pointer => 8, + .slice => 8, + .array => |array| { + const element_type = unit.types.get(array.type); + const alignment = element_type.getAbiAlignment(unit); + return alignment; + }, + else => |t| @panic(@tagName(t)), + }; +} + +const HomogeneousAggregate = struct { + type: Type.Index, + count: u32, +}; + +fn getTypeHomogeneousAggregate(ty: *Type, unit: *Unit) ?HomogeneousAggregate { + return switch (ty.*) { + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| { + for (struct_type.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + const field_type = unit.types.get(field.type); + while (field_type.* == .array) { + unreachable; + } + + if (getTypeHomogeneousAggregate(field_type, unit)) |homogeneous_aggregate| { + _ = homogeneous_aggregate; + unreachable; + } else { + return null; + } + } + unreachable; + }, + else => |t| @panic(@tagName(t)), + }, + .integer => |_| { + if (ty.is_homogeneous_base_type(unit)) { + unreachable; + } else { + return null; + } + }, else => |t| @panic(@tagName(t)), }; } @@ -2484,11 +2644,32 @@ pub const Type = union(enum) { fn getByteSize(ty: *Type, unit: *Unit) u32 { _ = unit; // autofix return switch (ty.*) { - .integer => |integer| @divExact(integer.bit_count, @bitSizeOf(u8)), + .integer => |integer| std.math.divCeil(u16, integer.bit_count, @bitSizeOf(u8)) catch unreachable, + .pointer => 8, else => |t| @panic(@tagName(t)), }; } + pub fn getAbiSize(ty: *Type, unit: *Unit) u32 { + return getTypeAbiSize(ty, unit); + } + + pub fn getAbiAlignment(ty: *Type, unit: *Unit) u32 { + return getTypeAbiAlignment(ty, unit); + } + + fn is_homogeneous_base_type(ty: *Type, unit: *Unit) bool { + _ = unit; + return switch (ty.*) { + .integer => false, + else => |t| @panic(@tagName(t)), + }; + } + + fn get_homogeneous_aggregate(ty: *Type, unit: *Unit) ?HomogeneousAggregate { + return getTypeHomogeneousAggregate(ty, unit); + } + fn getScope(ty: *Type, unit: *Unit) *Debug.Scope { return switch (ty.*) { .@"struct" => |struct_index| &unit.structs.get(struct_index).kind.@"struct".scope.scope, @@ -2501,6 +2682,14 @@ pub const Type = union(enum) { }; } + fn is_aggregate(ty: *Type) bool { + return switch (ty.*) { + .integer, .pointer => false, + .@"struct" => true, + else => |t| @panic(@tagName(t)), + }; + } + const Expect = union(enum) { none, type: Type.Index, @@ -2729,7 +2918,7 @@ pub const Type = union(enum) { pub const Instruction = union(enum) { add_overflow: AddOverflow, - argument_declaration: *Debug.Declaration.Argument, + abi_argument: u32, branch: Branch, block: Debug.Block.Index, // TODO @@ -2737,6 +2926,7 @@ pub const Instruction = union(enum) { cast: Cast, debug_checkpoint: DebugCheckPoint, debug_declare_local_variable: DebugDeclareLocalVariable, + debug_declare_argument: DebugDeclareArgument, extract_value: ExtractValue, insert_value: InsertValue, get_element_pointer: GEP, @@ -2745,6 +2935,7 @@ pub const Instruction = union(enum) { integer_binary_operation: Instruction.IntegerBinaryOperation, jump: Jump, load: Load, + memcpy: Memcpy, umin: Min, smin: Min, phi: Phi, @@ -2759,6 +2950,15 @@ pub const Instruction = union(enum) { trap, @"unreachable", + const Memcpy = struct{ + destination: V, + source: V, + destination_alignment: ?u32, + source_alignment: ?u32, + size: u32, + is_volatile: bool, + }; + const Switch = struct { condition: V, cases: UnpinnedArray(Case) = .{}, @@ -2825,6 +3025,11 @@ pub const Instruction = union(enum) { stack: Instruction.Index, }; + const DebugDeclareArgument = struct { + argument: *Debug.Declaration.Argument, + stack: Instruction.Index, + }; + const Syscall = struct { arguments: []const V, }; @@ -2904,6 +3109,7 @@ pub const Instruction = union(enum) { slice_to_nullable, slice_to_not_null, slice_coerce_to_zero_termination, + slice_zero_to_no_termination, truncate, pointer_to_array_to_pointer_to_many, error_union_type_int_to_pointer, @@ -2921,10 +3127,12 @@ pub const Instruction = union(enum) { const Load = struct { value: V, type: Type.Index, + alignment: ?u32 = null, }; const StackSlot = struct { type: Type.Index, + alignment: ?u32, }; const Store = struct { @@ -2966,6 +3174,8 @@ pub const Function = struct { // TODO: make this more efficient type: Type.Index, body: Debug.Block.Index, + return_pointer: Instruction.Index = .null, + alloca_index: u32 = 1, pub const List = BlockList(@This(), enum {}); pub usingnamespace @This().List.Index; @@ -2977,17 +3187,76 @@ pub const Function = struct { }; pub const Prototype = struct { - argument_types: []const Type.Index, - return_type: Type.Index, - attributes: Attributes, - calling_convention: CallingConvention, + argument_types: []const Type.Index = &.{}, + return_type: Type.Index = .null, + abi: Prototype.Abi = .{}, + attributes: Attributes = .{}, + calling_convention: CallingConvention = .auto, const Attributes = struct { - naked: bool, + naked: bool = false, }; const List = BlockList(@This(), enum {}); pub usingnamespace @This().List.Index; + + const Abi = struct { + return_type: Type.Index = .null, + parameter_types: []const Type.Index = &.{}, + return_type_abi: Function.AbiInfo = .{}, + parameter_types_abi: []const Function.AbiInfo = &.{}, + }; + }; + + pub const AbiInfo = struct { + indices: [2]u16 = .{ 0, 0 }, + kind: AbiKind = .direct, + attributes: AbiAttributes = .{}, + }; + + const AbiKind = union(enum) { + ignore, + direct, + direct_pair: [2]Type.Index, + direct_coerce: Type.Index, + direct_coerce_int, + direct_split_struct_i32, + expand_coerce, + indirect: struct { + type: Type.Index, + pointer: Type.Index, + alignment: u32, + }, + expand, + }; + + // const AbiType = union(enum) { + // type: Type.Index, + // integer_bit_count: u32, + // invalid, + // + // fn is_promotable_integer_or_bool(abi_type: AbiType, unit: *Unit) bool { + // switch (abi_type) { + // .type => |type_index| if (get_integer_or_bool(type_index, unit)) |integer| { + // return integer.bit_count < 32; + // }, + // } + // } + // + // fn get_integer_or_bool(type_index: Type.Index, unit: *Unit) ?Type.Integer { + // return switch (unit.types.get(type_index).*) { + // .integer => true, + // else => false, + // }; + // } + // }; + + const AbiAttributes = struct { + by_reg: bool = false, + zero_extend: bool = false, + sign_extend: bool = false, + realign: bool = false, + by_value: bool = false, }; }; @@ -2995,7 +3264,7 @@ pub const Struct = struct { kind: Kind, pub const Kind = union(enum) { - @"struct": StructDescriptor, + @"struct": Struct.Descriptor, @"union": struct { scope: Debug.Scope.Global, fields: UnpinnedArray(Struct.Field.Index) = .{}, @@ -3013,11 +3282,12 @@ pub const Struct = struct { type: Type.Index, padding: Type.Index, }, + two_struct: [2]Type.Index, + }; - pub const StructDescriptor = struct { - scope: Debug.Scope.Global, - fields: UnpinnedArray(Struct.Field.Index) = .{}, - }; + pub const Descriptor = struct { + scope: Debug.Scope.Global, + fields: UnpinnedArray(Struct.Field.Index) = .{}, }; pub const Field = struct { @@ -3066,6 +3336,7 @@ pub const V = struct { unresolved: Node.Index, undefined, void, + noreturn, type: Type.Index, bool: bool, comptime_int: ComptimeInt, @@ -3178,6 +3449,7 @@ pub const Debug = struct { }; pub const Argument = struct { declaration: Declaration, + index: u32, pub const List = BlockList(@This(), enum {}); pub usingnamespace List.Index; @@ -3296,6 +3568,7 @@ pub const IntrinsicId = enum { @"asm", //this is processed separately as it need special parsing cast, enum_to_int, + @"export", @"error", int_to_pointer, import, @@ -3800,6 +4073,31 @@ pub const Builder = struct { else => |t| @panic(@tagName(t)), } }, + .@"export" => { + assert(argument_node_list.len == 1); + const expression = try builder.resolveComptimeValue(unit, context, Type.Expect.none, Debug.Declaration.Global.Attributes.initMany(&.{.@"export"}), argument_node_list[0], null, .left); + switch (expression) { + .global => {}, + else => |t| @panic(@tagName(t)), + } + + return .{ + .value = .{ + .@"comptime" = .void, + }, + .type = .void, + }; + }, + .trap => { + assert(argument_node_list.len == 0); + try builder.buildTrap(unit, context); + return .{ + .value = .{ + .@"comptime" = .noreturn, + }, + .type = .noreturn, + }; + }, else => |t| @panic(@tagName(t)), } } @@ -3936,7 +4234,7 @@ pub const Builder = struct { assert(@intFromEnum(old_scope.kind) <= @intFromEnum(new_scope.kind)); - if (builder.current_basic_block != .null and (unit.function_definitions.get( builder.current_function).basic_blocks.length <= 1 or (unit.basic_blocks.get(builder.current_basic_block).instructions.length > 0 or unit.basic_blocks.get(builder.current_basic_block).predecessors.length > 0))) { + if (builder.current_basic_block != .null and (unit.function_definitions.get(builder.current_function).basic_blocks.length <= 1 or (unit.basic_blocks.get(builder.current_basic_block).instructions.length > 0 or unit.basic_blocks.get(builder.current_basic_block).predecessors.length > 0))) { assert(@intFromEnum(old_scope.kind) >= @intFromEnum(Debug.Scope.Kind.function)); const instruction = try unit.instructions.append(context.my_allocator, .{ .push_scope = .{ @@ -3957,7 +4255,7 @@ pub const Builder = struct { assert(@intFromEnum(old_scope.kind) >= @intFromEnum(new_scope.kind)); - if (builder.current_basic_block != .null and (unit.function_definitions.get( builder.current_function).basic_blocks.length <= 1 or (unit.basic_blocks.get(builder.current_basic_block).instructions.length > 0 or unit.basic_blocks.get(builder.current_basic_block).predecessors.length > 0))) { + if (builder.current_basic_block != .null and (unit.function_definitions.get(builder.current_function).basic_blocks.length <= 1 or (unit.basic_blocks.get(builder.current_basic_block).instructions.length > 0 or unit.basic_blocks.get(builder.current_basic_block).predecessors.length > 0))) { const instruction = try unit.instructions.append(context.my_allocator, .{ .pop_scope = .{ .old = old_scope, @@ -4081,6 +4379,24 @@ pub const Builder = struct { } } + fn createStackVariable(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, alignment: ?u32) !Instruction.Index { + const stack = try unit.instructions.append(context.my_allocator, .{ + .stack_slot = .{ + .type = type_index, + .alignment = alignment, + }, + }); + const function_definition = unit.function_definitions.get(builder.current_function); + + const basic_block_index = function_definition.basic_blocks.slice()[0]; + const basic_block = unit.basic_blocks.get(basic_block_index); + try basic_block.instructions.insert(context.my_allocator, function_definition.alloca_index, stack); + + function_definition.alloca_index += 1; + + return stack; + } + fn appendInstruction(builder: *Builder, unit: *Unit, context: *const Context, instruction_index: Instruction.Index) !void { // if (@intFromEnum(instruction_index) == 430) @breakpoint(); switch (unit.instructions.get(instruction_index).*) { @@ -4088,6 +4404,9 @@ pub const Builder = struct { .pointer => unreachable, else => {}, }, + .store => |store| { + if (store.source.value == .runtime and @intFromEnum(store.source.value.runtime) == 0xaaaa_aaaa) @breakpoint(); + }, else => {}, } const basic_block = unit.basic_blocks.get(builder.current_basic_block); @@ -4109,7 +4428,7 @@ pub const Builder = struct { }; }; - fn referenceGlobalDeclaration(builder: *Builder, unit: *Unit, context: *const Context, scope: *Debug.Scope, declaration: *Debug.Declaration) !*Debug.Declaration.Global { + fn referenceGlobalDeclaration(builder: *Builder, unit: *Unit, context: *const Context, scope: *Debug.Scope, declaration: *Debug.Declaration, global_attribute_override: Debug.Declaration.Global.Attributes) !*Debug.Declaration.Global { // TODO: implement this assert(declaration.kind == .global); const old_context = builder.startContextSwitch(.{ @@ -4136,12 +4455,24 @@ pub const Builder = struct { }, }; - global_declaration.initial_value = try builder.resolveComptimeValue(unit, context, type_expect, global_declaration.attributes, declaration_node_index, global_declaration); + inline for (@typeInfo(Debug.Declaration.Global.Attribute).Enum.fields) |attribute_enum_field| { + const attribute = @field(Debug.Declaration.Global.Attribute, attribute_enum_field.name); + if (global_attribute_override.contains(attribute)) { + global_declaration.attributes.insert(attribute); + } + } + + global_declaration.initial_value = try builder.resolveComptimeValue(unit, context, type_expect, global_declaration.attributes, declaration_node_index, global_declaration, .right); switch (declaration.type) { .null => { assert(global_declaration.type_node_index == .null); declaration.type = global_declaration.initial_value.getType(unit); + + if (global_declaration.initial_value == .function_definition) { + const function_definition = unit.function_definitions.get(global_declaration.initial_value.function_definition); + assert(declaration.type == function_definition.type); + } }, else => {}, } @@ -4185,6 +4516,13 @@ pub const Builder = struct { else => {}, } + inline for (@typeInfo(Debug.Declaration.Global.Attribute).Enum.fields) |attribute_enum_field| { + const attribute = @field(Debug.Declaration.Global.Attribute, attribute_enum_field.name); + if (global_attribute_override.contains(attribute)) { + assert(global_declaration.attributes.contains(attribute)); + } + } + builder.endContextSwitch(old_context); return global_declaration; @@ -4217,11 +4555,6 @@ pub const Builder = struct { } fn resolveImport(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, arguments: []const Node.Index) !Debug.File.Index { - switch (type_expect) { - .none => {}, - .type => |type_index| if (type_index != .type) @panic("expected type"), - else => unreachable, - } if (arguments.len != 1) { @panic("Import argument mismatch"); } @@ -4234,7 +4567,17 @@ pub const Builder = struct { const string_literal_bytes = try unit.fixupStringLiteral(context, argument_node.token); - const import_file = try unit.importFile(context, builder.current_file, string_literal_bytes); + return try builder.resolveImportStringLiteral(unit, context, type_expect, string_literal_bytes); + } + + fn resolveImportStringLiteral(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, import_path: []const u8) !Debug.File.Index { + switch (type_expect) { + .none => {}, + .type => |type_index| if (type_index != .type) @panic("expected type"), + else => unreachable, + } + + const import_file = try unit.importFile(context, builder.current_file, import_path); const file_index = import_file.file.index; const file = unit.files.get(file_index); @@ -4255,535 +4598,6 @@ pub const Builder = struct { cannot_evaluate, }; - /// Last value is used to cache types being analyzed so we dont hit stack overflow - fn resolveComptimeValue(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, global_attributes: Debug.Declaration.Global.Attributes, node_index: Node.Index, maybe_global: ?*Debug.Declaration.Global) anyerror!V.Comptime { - const node = unit.getNode(node_index); - switch (node.id) { - .intrinsic => { - const argument_node_list = unit.getNodeList(node.left); - const intrinsic_id: IntrinsicId = @enumFromInt(Node.unwrap(node.right)); - switch (intrinsic_id) { - .import => { - const file_index = try builder.resolveImport(unit, context, type_expect, argument_node_list); - const file = unit.files.get(file_index); - return .{ - .type = file.type, - }; - }, - else => |t| @panic(@tagName(t)), - } - }, - .field_access => { - const result = try builder.resolveFieldAccess(unit, context, type_expect, node_index, .right); - return switch (result.value) { - .@"comptime" => |ct| ct, - else => @panic("Expected comptime value, found runtime value"), - }; - }, - .keyword_false, - .keyword_true, - => return .{ - .bool = node.id == .keyword_true, - }, - .function_definition => { - const current_basic_block = builder.current_basic_block; - defer builder.current_basic_block = current_basic_block; - builder.current_basic_block = .null; - - const old_exit_blocks = builder.exit_blocks; - defer builder.exit_blocks = old_exit_blocks; - builder.exit_blocks = .{}; - - const old_phi_node = builder.return_phi; - defer builder.return_phi = old_phi_node; - builder.return_phi = .null; - - const old_return_block = builder.return_block; - defer builder.return_block = old_return_block; - builder.return_block = .null; - - const function_prototype_node_index = node.left; - const body_node_index = node.right; - - const function_type_index = try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes); - - const old_function = builder.current_function; - const token_debug_info = builder.getTokenDebugInfo(unit, node.token); - builder.current_function = try unit.function_definitions.append(context.my_allocator, .{ - .type = function_type_index, - .body = undefined, - .scope = .{ - .scope = Debug.Scope{ - .line = token_debug_info.line, - .column = token_debug_info.column, - .kind = .function, - .local = true, - .level = builder.current_scope.level + 1, - .file = builder.current_file, - }, - }, - }); - - defer builder.current_function = old_function; - - const function = unit.function_definitions.get(builder.current_function); - - builder.last_check_point = .{}; - assert(builder.current_scope.kind == .file_container or builder.current_scope.kind == .file or builder.current_scope.kind == .container); - try builder.pushScope(unit, context, &function.scope.scope); - defer builder.popScope(unit, context) catch unreachable; - - const entry_basic_block = try builder.newBasicBlock(unit, context); - builder.current_basic_block = entry_basic_block; - defer builder.current_basic_block = .null; - - const body_node = unit.getNode(body_node_index); - try builder.insertDebugCheckPoint(unit, context, body_node.token); - - const function_prototype_index = unit.types.get(function_type_index).function; - // Get argument declarations into scope - const function_prototype_node = unit.getNode(function_prototype_node_index); - - if (function_prototype_node.left != .null) { - const argument_node_list = unit.getNodeList(function_prototype_node.left); - const function_prototype = unit.function_prototypes.get(function_prototype_index); - const argument_types = function_prototype.argument_types; - - for (argument_node_list, argument_types) |argument_node_index, argument_type_index| { - const argument_node = unit.getNode(argument_node_index); - assert(argument_node.id == .argument_declaration); - - const argument_name = unit.getExpectedTokenBytes(argument_node.token, .identifier); - const argument_name_hash = try unit.processIdentifier(context, argument_name); - - const look_in_parent_scopes = true; - if (builder.current_scope.lookupDeclaration(argument_name_hash, look_in_parent_scopes)) |_| { - @panic("Symbol already in scope"); - // std.debug.panic("Symbol with name '{s}' already declarared on scope", .{argument_name}); - } - - const argument_token_debug_info = builder.getTokenDebugInfo(unit, argument_node.token); - const argument_declaration_index = try unit.argument_declarations.append(context.my_allocator, .{ - .declaration = .{ - .scope = builder.current_scope, - .name = argument_name_hash, - .type = argument_type_index, - .mutability = .@"const", - .line = argument_token_debug_info.line, - .column = argument_token_debug_info.column, - .kind = .argument, - }, - }); - comptime assert(@TypeOf(argument_declaration_index) == Debug.Declaration.Argument.Index); - const argument = unit.argument_declarations.get(argument_declaration_index); - - try builder.current_scope.declarations.put_no_clobber(context.my_allocator, argument_name_hash, &argument.declaration); - - const argument_instruction = try unit.instructions.append(context.my_allocator, .{ - .argument_declaration = argument, - }); - - try builder.appendInstruction(unit, context, argument_instruction); - - try function.scope.argument_map.put_no_clobber(context.my_allocator, argument, argument_instruction); - } - } - - if (body_node.id == .block) { - function.body = try builder.resolveBlock(unit, context, body_node_index); - - const cbb = unit.basic_blocks.get(builder.current_basic_block); - const function_prototype = unit.function_prototypes.get(function_prototype_index); - const return_type = function_prototype.return_type; - - if (!cbb.terminated and (cbb.instructions.length > 0 or cbb.predecessors.length > 0)) { - if (builder.return_block == .null) { - switch (function_prototype.attributes.naked) { - true => { - assert(return_type == .noreturn); - try builder.buildTrap(unit, context); - }, - false => switch (return_type) { - .void => try builder.buildRet(unit, context, .{ - .value = .{ - .@"comptime" = .void, - }, - .type = .void, - }), - .noreturn => try builder.buildTrap(unit, context), - else => switch (unit.types.get(return_type).*) { - .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { - .error_union => |error_union| { - switch (error_union.type) { - .void => { - assert(error_union.abi == error_union.union_for_type); - const undefined_value = V{ - .value = .{ - .@"comptime" = .undefined, - }, - .type = return_type, - }; - const insert = try unit.instructions.append(context.my_allocator, .{ - .insert_value = .{ - .expression = undefined_value, - .index = 1, - .new_value = .{ - .value = .{ - .@"comptime" = .{ - .bool = false, - }, - }, - .type = .bool, - }, - }, - }); - try builder.appendInstruction(unit, context, insert); - - try builder.buildRet(unit, context, .{ - .value = .{ - .runtime = insert, - }, - .type = return_type, - }); - }, - else => unreachable, - } - }, - else => |t| @panic(@tagName(t)), - }, - else => |t| @panic(@tagName(t)), - }, - }, - } - } else { - assert(builder.return_phi != .null); - assert(builder.return_block != builder.current_basic_block); - - const phi = &unit.instructions.get(builder.return_phi).phi; - - switch (return_type) { - .void => unreachable, - .noreturn => unreachable, - else => switch (unit.types.get(return_type).*) { - .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { - .error_union => |error_union| { - if (error_union.type == .void or - // TODO: is this correct? - error_union.type == .noreturn) - { - const return_value = try unit.instructions.append(context.my_allocator, .{ - .insert_value = .{ - .expression = .{ - .value = .{ - .@"comptime" = .undefined, - }, - .type = return_type, - }, - .index = 1, - .new_value = .{ - .value = .{ - .@"comptime" = .{ - .bool = false, - }, - }, - .type = .bool, - }, - }, - }); - try builder.appendInstruction(unit, context, return_value); - - try phi.addIncoming(context, .{ - .value = .{ - .runtime = return_value, - }, - .type = return_type, - }, builder.current_basic_block); - - try builder.jump(unit, context, builder.return_block); - } else { - try unit.dumpFunctionDefinition(builder.current_function); - unreachable; - } - }, - else => |t| @panic(@tagName(t)), - }, - else => { - try unit.dumpFunctionDefinition(builder.current_function); - unreachable; - }, - }, - } - } - } - - const function_definition_index = builder.current_function; - - return .{ - .function_definition = function_definition_index, - }; - } else { - @panic("Function body is expected to be a block"); - } - }, - .number_literal => switch (std.zig.parseNumberLiteral(unit.getExpectedTokenBytes(node.token, .number_literal))) { - .int => |integer| { - return .{ - .comptime_int = .{ - .value = integer, - .signedness = .unsigned, - }, - }; - }, - else => |t| @panic(@tagName(t)), - }, - .undefined => { - return .undefined; - }, - .enum_type, .struct_type, .bitfield_type => { - const type_index = try builder.resolveContainerType(unit, context, node_index, switch (node.id) { - .enum_type => .@"enum", - .struct_type => .@"struct", - .bitfield_type => .bitfield, - else => unreachable, - }, maybe_global); - return .{ - .type = type_index, - }; - }, - .@"switch" => { - const result = try builder.resolveSwitch(unit, context, type_expect, node_index, .right); - switch (result.value) { - .@"comptime" => |ct| { - return ct; - }, - .runtime => unreachable, - else => unreachable, - } - }, - .identifier => { - const identifier = unit.getExpectedTokenBytes(node.token, .identifier); - const side: Side = switch (type_expect) { - .none => unreachable, - .type => |type_index| switch (unit.types.get(type_index).*) { - .type => .right, - else => |t| @panic(@tagName(t)), - }, - else => unreachable, - }; - const resolved_value = try builder.resolveIdentifier(unit, context, type_expect, identifier, side); - return switch (resolved_value.value) { - .@"comptime" => |ct| ct, - .runtime => return error.cannot_evaluate, - else => unreachable, - }; - }, - .signed_integer_type => { - const result = try builder.resolveIntegerType(unit, context, node_index); - return .{ - .type = result, - }; - }, - .compare_greater_equal => { - const left = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null); - const left_type = left.getType(unit); - const right = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = left_type }, .{}, node.right, null); - _ = right; // autofix - unreachable; - }, - .add => { - const left = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null); - const left_type = left.getType(unit); - const right = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = left_type }, .{}, node.right, null); - switch (left) { - .comptime_int => |left_ct_int| { - assert(left_ct_int.signedness == .unsigned); - const left_value = left_ct_int.value; - switch (right) { - .comptime_int => |right_ct_int| { - assert(right_ct_int.signedness == .unsigned); - const right_value = right_ct_int.value; - const result = left_value + right_value; - return .{ - .comptime_int = .{ - .value = result, - .signedness = .unsigned, - }, - }; - }, - else => |t| @panic(@tagName(t)), - } - }, - else => |t| @panic(@tagName(t)), - } - }, - .empty_container_literal_guess => { - assert(node.left != .null); - assert(node.right != .null); - const container_type = try builder.resolveType(unit, context, node.left); - const node_list = unit.getNodeList(node.right); - assert(node_list.len == 0); - const result = try builder.resolveContainerLiteral(unit, context, node_list, container_type); - return switch (result.value) { - .@"comptime" => |ct| ct, - else => |t| @panic(@tagName(t)), - }; - }, - .anonymous_container_literal => { - assert(node.left == .null); - assert(node.right != .null); - switch (type_expect) { - .type => |type_index| { - const node_list = unit.getNodeList(node.right); - const result = try builder.resolveContainerLiteral(unit, context, node_list, type_index); - return switch (result.value) { - .@"comptime" => |ct| ct, - else => |t| @panic(@tagName(t)), - }; - }, - else => |t| @panic(@tagName(t)), - } - }, - .function_prototype => { - const function_prototype = try builder.resolveFunctionPrototype(unit, context, node_index, global_attributes); - if (global_attributes.contains(.@"extern")) { - return .{ - .function_declaration = function_prototype, - }; - } else { - unreachable; - } - }, - .error_type => { - assert(node.left != .null); - const nodes = unit.getNodeList(node.left); - if (nodes.len == 0) { - unreachable; - } - - const token_debug_info = builder.getTokenDebugInfo(unit, node.token); - const error_type_index = try unit.types.append(context.my_allocator, .{ - .integer = .{ - .signedness = .unsigned, - .bit_count = 32, - .kind = .{ - .@"error" = .{ - .scope = .{ - .scope = .{ - .file = builder.current_file, - .line = token_debug_info.line, - .column = token_debug_info.column, - .kind = .container, - .local = false, - .level = builder.current_scope.level + 1, - .parent = builder.current_scope, - }, - }, - .fields = try UnpinnedArray(Type.Error.Field.Index).initialize_with_capacity(context.my_allocator, @intCast(nodes.len)), - .id = unit.error_count, - }, - }, - }, - }); - unit.error_count += 1; - - const error_type = &unit.types.get(error_type_index).integer.kind.@"error"; - for (nodes, 0..) |field_node_index, index| { - const field_node = unit.getNode(field_node_index); - const identifier = unit.getExpectedTokenBytes(field_node.token, .identifier); - const hash = try unit.processIdentifier(context, identifier); - const error_field_index = try unit.error_fields.append(context.my_allocator, .{ - .name = hash, - .type = error_type_index, - .value = index, - }); - error_type.fields.append_with_capacity(error_field_index); - } - - return .{ - .type = error_type_index, - }; - }, - .dot_literal => { - switch (type_expect) { - .type => |type_index| { - const expected_type = unit.types.get(type_index); - const identifier = unit.getExpectedTokenBytes(Token.addInt(node.token, 1), .identifier); - const hash = try unit.processIdentifier(context, identifier); - switch (expected_type.*) { - .integer => |*integer| switch (integer.kind) { - .@"enum" => |*enum_type| { - for (enum_type.fields.slice()) |field_index| { - const field = unit.enum_fields.get(field_index); - if (field.name == hash) { - return .{ - .enum_value = field_index, - }; - } - } else { - unreachable; - } - }, - .@"error" => |*error_type| { - for (error_type.fields.slice()) |field_index| { - const field = unit.error_fields.get(field_index); - if (field.name == hash) { - return .{ - .error_value = field_index, - }; - } - } else { - unreachable; - } - }, - else => |t| @panic(@tagName(t)), - }, - else => |t| @panic(@tagName(t)), - } - }, - else => |t| @panic(@tagName(t)), - } - }, - .address_of => { - assert(node.left != .null); - assert(node.right == .null); - - const appointee = unit.getNode(node.left); - switch (appointee.id) { - .anonymous_empty_literal => switch (type_expect) { - .type => |type_index| switch (unit.types.get(type_index).*) { - .slice => |slice| { - _ = slice; // autofix - var field_list = try UnpinnedArray(V.Comptime).initialize_with_capacity(context.my_allocator, 2); - - field_list.append_with_capacity(.undefined); - field_list.append_with_capacity(V.Comptime{ - .constant_int = .{ - .value = 0, - }, - }); - - const constant_slice = try unit.constant_slices.append(context.my_allocator, .{ - .array = null, - .start = 0, - .end = 0, - .type = type_index, - }); - - return .{ - .constant_slice = constant_slice, - }; - }, - else => |t| @panic(@tagName(t)), - }, - else => |t| @panic(@tagName(t)), - }, - else => |t| @panic(@tagName(t)), - } - }, - else => |t| @panic(@tagName(t)), - } - } - fn referenceArgumentDeclaration(builder: *Builder, unit: *Unit, context: *const Context, scope: *Debug.Scope, declaration: *Debug.Declaration) !V { _ = builder; // autofix assert(declaration.kind == .argument); @@ -4839,6 +4653,7 @@ pub const Builder = struct { slice_var_to_const, slice_to_nullable, slice_coerce_to_zero_termination, + slice_zero_to_no_termination, materialize_int, optional_wrap, sign_extend, @@ -5011,7 +4826,7 @@ pub const Builder = struct { } } else { if (destination_slice.termination == .none) { - return .slice_coerce_to_zero_termination; + return .slice_zero_to_no_termination; } else { unreachable; } @@ -5089,7 +4904,7 @@ pub const Builder = struct { right, }; - fn resolveIdentifier(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, identifier: []const u8, side: Side) !V { + fn resolveIdentifier(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, identifier: []const u8, global_attributes: Debug.Declaration.Global.Attributes, side: Side) !V { const hash = try unit.processIdentifier(context, identifier); const look_in_parent_scopes = true; @@ -5101,7 +4916,7 @@ pub const Builder = struct { .file, .container, => b: { - const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration); + const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, global_attributes); const pointer_to_global = try unit.getPointerType(context, .{ .type = global.declaration.type, .termination = switch (type_expect) { @@ -5477,12 +5292,7 @@ pub const Builder = struct { }); try builder.appendInstruction(unit, context, final_error_union); - const support_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = error_union.union_for_error, - }, - }); - try builder.appendInstruction(unit, context, support_alloca); + const support_alloca = try builder.createStackVariable(unit, context, error_union.union_for_error, null); const pointer_type = try unit.getPointerType(context, .{ .type = error_union.union_for_error, @@ -5535,6 +5345,23 @@ pub const Builder = struct { .error_union_to_all_error_union => unreachable, .error_union_same_error => unreachable, .error_to_all_errors => unreachable, + .slice_zero_to_no_termination => { + const cast = try unit.instructions.append(context.my_allocator, .{ + .cast = .{ + .id = .slice_zero_to_no_termination, + .value = v, + .type = expected_type_index, + }, + }); + + try builder.appendInstruction(unit, context, cast); + return .{ + .value = .{ + .runtime = cast, + }, + .type = expected_type_index, + }; + }, } }, .array => |expected_array_descriptor| { @@ -5877,7 +5704,7 @@ pub const Builder = struct { var termination = Type.Termination.none; const len_node = unit.getNode(attribute_node_list[0]); const len = switch (len_node.id) { - else => switch (try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .usize }, .{}, attribute_node_list[0], null)) { + else => switch (try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .usize }, .{}, attribute_node_list[0], null, .right)) { .comptime_int => |ct_int| ct_int.value, .constant_int => |constant_int| constant_int.value, else => |t| @panic(@tagName(t)), @@ -5917,7 +5744,7 @@ pub const Builder = struct { .usize_type => .usize, .void_type => .void, .identifier, .field_access => { - const resolved_type_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .type }, .{}, node_index, null); + const resolved_type_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .type }, .{}, node_index, null, .right); return resolved_type_value.type; }, .bool_type => .bool, @@ -6120,18 +5947,8 @@ pub const Builder = struct { const attribute_node_list = attribute_and_return_type_node_list[0 .. attribute_and_return_type_node_list.len - 1]; const return_type_node_index = attribute_and_return_type_node_list[attribute_and_return_type_node_list.len - 1]; - const function_prototype_index = try unit.function_prototypes.append(context.my_allocator, .{ - .argument_types = &.{}, - .return_type = .null, - .attributes = .{ - // .@"export" = false, - .naked = false, - }, - .calling_convention = switch (global_attributes.contains(.@"export") or global_attributes.contains(.@"extern")) { - true => .c, - false => .auto, - }, - }); + const function_prototype_index = try unit.function_prototypes.append(context.my_allocator, .{}); + const function_prototype = unit.function_prototypes.get(function_prototype_index); var is_naked: bool = false; @@ -6140,11 +5957,61 @@ pub const Builder = struct { const attribute_node = unit.getNode(attribute_node_index); switch (attribute_node.id) { .function_attribute_naked => is_naked = true, + .function_attribute_cc => { + if (unit.cc_type == .null) { + const std_file_index = try builder.resolveImportStringLiteral(unit, context, Type.Expect{ .type = .type }, "std"); + const std_file = unit.files.get(std_file_index); + const std_file_struct_index = unit.types.get(std_file.type).@"struct"; + const std_file_struct = unit.structs.get(std_file_struct_index); + const builtin_hash = try unit.processIdentifier(context, "builtin"); + + const look_in_parent_scopes = false; + if (std_file_struct.kind.@"struct".scope.scope.lookupDeclaration(builtin_hash, look_in_parent_scopes)) |lookup| { + const builtin_declaration = try builder.referenceGlobalDeclaration(unit, context, &std_file_struct.kind.@"struct".scope.scope, lookup.declaration, .{}); + switch (builtin_declaration.initial_value) { + .type => |builtin_type_index| { + const builtin_type_struct_index = unit.types.get(builtin_type_index).@"struct"; + const builtin_type_struct = &unit.structs.get(builtin_type_struct_index).kind.@"struct"; + const cc_hash = try unit.processIdentifier(context, "CallingConvention"); + if (builtin_type_struct.scope.scope.lookupDeclaration(cc_hash, look_in_parent_scopes)) |cc_lookup| { + const cc_global = try builder.referenceGlobalDeclaration(unit, context, cc_lookup.scope, cc_lookup.declaration, .{}); + unit.cc_type = cc_global.initial_value.type; + } else { + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + } + } else { + @panic("Internal compiler error"); + } + } + + assert(unit.cc_type != .null); + const cc = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = unit.cc_type }, .{}, attribute_node.left, null, .right); + switch (cc) { + .enum_value => |enum_field_index| { + const enum_field = unit.enum_fields.get(enum_field_index); + const enum_name = unit.getIdentifier(enum_field.name); + + function_prototype.calling_convention = data_structures.enumFromString(Function.CallingConvention, enum_name) orelse unreachable; + }, + else => |t| @panic(@tagName(t)), + } + }, else => |t| @panic(@tagName(t)), } } - const function_prototype = unit.function_prototypes.get(function_prototype_index); + if (global_attributes.contains(.@"export") or global_attributes.contains(.@"extern")) { + if (function_prototype.calling_convention == .auto) { + @panic("Function prototype must have a non-automatic calling calling convention"); + } + } + + function_prototype.attributes = .{ + .naked = is_naked, + }; if (node.left != .null) { const argument_node_list = unit.getNodeList(node.left); @@ -6161,12 +6028,10 @@ pub const Builder = struct { function_prototype.argument_types = argument_types.slice(); } - function_prototype.attributes = .{ - .naked = is_naked, - }; - function_prototype.return_type = try builder.resolveType(unit, context, return_type_node_index); + try builder.resolveFunctionPrototypeAbi(unit, context, function_prototype); + const function_prototype_type_index = try unit.types.append(context.my_allocator, .{ .function = function_prototype_index, }); @@ -6174,6 +6039,867 @@ pub const Builder = struct { return function_prototype_type_index; } + fn classify_argument_type_aarch64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index) Function.AbiInfo { + _ = builder; + if (type_index == .void or type_index == .noreturn) return Function.AbiInfo{ + .kind = .ignore, + }; + + // TODO: + const is_illegal_vector = false; + if (is_illegal_vector) { + unreachable; + } + + const ty = unit.types.get(type_index); + const size = ty.getAbiSize(unit); + + if (!ty.is_aggregate()) { + const extend = switch (ty.*) { + else => |t| @panic(@tagName(t)), + .integer => |integer| integer.bit_count < 32, + .pointer => false, + }; + + if (extend) { + const signed = switch (ty.*) { + else => |t| @panic(@tagName(t)), + .integer => |integer| integer.signedness == .signed, + .pointer => false, + }; + + return Function.AbiInfo{ + .kind = .direct, + .attributes = .{ + .zero_extend = !signed, + .sign_extend = signed, + }, + }; + } else { + return Function.AbiInfo{ + .kind = .direct, + }; + } + } else { + assert(size > 0); + + if (ty.get_homogeneous_aggregate(unit)) |homogeneous_aggregate| { + _ = homogeneous_aggregate; + unreachable; + } else if (size <= 16) { + const base_alignment = ty.getAbiAlignment(unit); + const is_appcs = false; + const alignment: u32 = switch (is_appcs) { + true => if (base_alignment < 16) 8 else 16, + false => @max(base_alignment, 8), + }; + assert(alignment == 8 or alignment == 16); + + const aligned_size = data_structures.align_forward(size, alignment); + if (alignment == 16) { + unreachable; + } else { + const m = aligned_size / alignment; + if (m > 1) { + const array_type = unit.getArrayType(context, .{ + .type = .u64, + .count = m, + .termination = .none, + }) catch unreachable; + return .{ + .kind = .{ + .direct_coerce = array_type, + }, + }; + } else { + return .{ + .kind = .{ + .direct_coerce = .u64, + }, + }; + } + } + } else { + const alignment = ty.getAbiAlignment(unit); + assert(alignment > 0); + const pointer_type = unit.getPointerType(context, .{ + .type = type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }) catch unreachable; + return .{ + .kind = .{ + .indirect = .{ + .type = type_index, + .pointer = pointer_type, + .alignment = alignment, + }, + }, + }; + } + } + } + + fn classify_return_type_aarch64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index) Function.AbiInfo { + _ = builder; + if (type_index == .void or type_index == .noreturn) return Function.AbiInfo{ + .kind = .ignore, + }; + const ty = unit.types.get(type_index); + const size = ty.getAbiSize(unit); + + const is_vector = false; + if (is_vector and size > 16) { + unreachable; + } + + if (!ty.is_aggregate()) { + const extend = switch (ty.*) { + else => |t| @panic(@tagName(t)), + .integer => |integer| integer.bit_count < 32, + .pointer => false, + }; + + if (extend) { + const signed = switch (ty.*) { + else => |t| @panic(@tagName(t)), + .integer => |integer| integer.signedness == .signed, + .pointer => false, + }; + + return Function.AbiInfo{ + .kind = .direct, + .attributes = .{ + .zero_extend = !signed, + .sign_extend = signed, + }, + }; + } else { + return Function.AbiInfo{ + .kind = .direct, + }; + } + } else { + assert(size > 0); + const is_variadic = false; + const is_aarch64_32 = false; + const maybe_homogeneous_aggregate = ty.get_homogeneous_aggregate(unit); + + if (maybe_homogeneous_aggregate != null and !(is_aarch64_32 and is_variadic)) { + unreachable; + } else if (size <= 16) { + if (size <= 8 and @import("builtin").cpu.arch.endian() == .little) { + return .{ + .kind = .{ + .direct_coerce = unit.getIntegerType(context, .{ + .bit_count = @intCast(size * 8), + .signedness = .unsigned, + .kind = .materialized_int, + }) catch unreachable, + }, + }; + } else { + const alignment = ty.getAbiAlignment(unit); + const aligned_size: u16 = @intCast(data_structures.align_forward(size, 8)); + if (alignment < 16 and aligned_size == 16) { + const array_type = unit.getArrayType(context, .{ + .count = 2, + .type = .u64, + .termination = .none, + }) catch unreachable; + return .{ + .kind = .{ + .direct_coerce = array_type, + }, + }; + } else { + const integer_t = unit.getIntegerType(context, .{ + .kind = .materialized_int, + .bit_count = aligned_size * 8, + .signedness = .unsigned, + }) catch unreachable; + return .{ + .kind = .{ + .direct_coerce = integer_t, + }, + }; + } + } + } else { + const alignment = ty.getAbiAlignment(unit); + assert(alignment > 0); + const pointer_type = unit.getPointerType(context, .{ + .type = type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }) catch unreachable; + return .{ + .kind = .{ + .indirect = .{ + .type = type_index, + .pointer = pointer_type, + .alignment = alignment, + }, + }, + .attributes = .{ + .by_value = true, + }, + }; + } + } + } + + fn resolveFunctionPrototypeAbiAarch64(builder: *Builder, unit: *Unit, context: *const Context, function_prototype: *Function.Prototype, parameter_types_abi: *UnpinnedArray(Function.AbiInfo)) !void { + const return_type_abi = builder.classify_return_type_aarch64(unit, context, function_prototype.return_type); + for (function_prototype.argument_types) |argument_type_index| { + const abi_arg = builder.classify_argument_type_aarch64(unit, context, argument_type_index); + parameter_types_abi.append_with_capacity(abi_arg); + } + function_prototype.abi.return_type_abi = return_type_abi; + function_prototype.abi.parameter_types_abi = parameter_types_abi.slice(); + } + + fn resolveFunctionPrototypeAbi(builder: *Builder, unit: *Unit, context: *const Context, function_prototype: *Function.Prototype) !void { + switch (function_prototype.calling_convention) { + .auto => { + function_prototype.abi.return_type = function_prototype.return_type; + function_prototype.abi.parameter_types = function_prototype.argument_types; + function_prototype.abi.return_type_abi = .{ + .kind = if (function_prototype.return_type == .void or function_prototype.return_type == .noreturn) .ignore else .direct, + }; + + var parameter_abis = try UnpinnedArray(Function.AbiInfo).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.argument_types.len)); + for (function_prototype.argument_types, 0..) |_, i| { + const index: u16 = @intCast(i); + parameter_abis.append_with_capacity(.{ + .kind = .direct, + .indices = .{ index, index + 1 }, + }); + } + + function_prototype.abi.parameter_types_abi = parameter_abis.slice(); + }, + .c => { + var parameter_types_abi = try UnpinnedArray(Function.AbiInfo).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.argument_types.len)); + switch (unit.descriptor.arch) { + .x86_64 => switch (unit.descriptor.os) { + .linux => try builder.resolveFunctionPrototypeAbiSystemVx86_64(unit, context, function_prototype, ¶meter_types_abi), + else => |t| @panic(@tagName(t)), + }, + .aarch64 => try builder.resolveFunctionPrototypeAbiAarch64(unit, context, function_prototype, ¶meter_types_abi), + } + + var abi_parameter_types = UnpinnedArray(Type.Index){}; + const abi_return_type = switch (function_prototype.abi.return_type_abi.kind) { + .ignore => function_prototype.return_type, + .direct_pair => |direct_pair| try unit.getTwoStruct(context, direct_pair), + .direct => function_prototype.return_type, + .indirect => |indirect| b: { + // const pointer_type = try unit.getPointerType(context, .{ + // .type = indirect.type, + // .termination = .none, + // .mutability = .@"var", + // .many = false, + // .nullable = false, + // }); + try abi_parameter_types.append(context.my_allocator, indirect.pointer); + break :b .void; + }, + .direct_coerce => |coerced_type| coerced_type, + else => |t| @panic(@tagName(t)), + }; + + for (parameter_types_abi.slice(), function_prototype.argument_types) |*parameter_abi, parameter_type_index| { + const start: u16 = @intCast(abi_parameter_types.length); + switch (parameter_abi.kind) { + .direct => try abi_parameter_types.append(context.my_allocator, parameter_type_index), + .direct_coerce => |coerced_type| try abi_parameter_types.append(context.my_allocator, coerced_type), + .direct_pair => |direct_pair| { + try abi_parameter_types.append(context.my_allocator, direct_pair[0]); + try abi_parameter_types.append(context.my_allocator, direct_pair[1]); + }, + .indirect => |indirect| { + // const pointer_type = try unit.getPointerType(context, .{ + // .type = indirect.type, + // .termination = .none, + // .mutability = .@"var", + // .many = false, + // .nullable = false, + // }); + try abi_parameter_types.append(context.my_allocator, indirect.pointer); + }, + else => |t| @panic(@tagName(t)), + } + + const end: u16 = @intCast(abi_parameter_types.length); + parameter_abi.indices = .{ start, end }; + } + + function_prototype.abi.return_type = abi_return_type; + function_prototype.abi.parameter_types = abi_parameter_types.slice(); + }, + } + + assert(function_prototype.return_type != .null); + assert(function_prototype.abi.return_type != .null); + } + + fn resolveFunctionPrototypeAbiSystemVx86_64(builder: *Builder, unit: *Unit, context: *const Context, function_prototype: *Function.Prototype, parameter_types_abi: *UnpinnedArray(Function.AbiInfo)) !void { + const return_abi = builder.classify_return_type_systemv_x86_64(unit, context, function_prototype.return_type); + var available_registers = SystemV_x86_64_Registers{ + .gp_registers = 6, + .sse_registers = 8, + }; + if (return_abi.kind == .indirect) { + available_registers.gp_registers -= 1; + } + + const return_by_reference = false; + if (return_by_reference) { + unreachable; + } + + for (function_prototype.argument_types) |parameter_type_index| { + const parameter_classification = builder.classify_argument_type_systemv_x86_64(unit, context, parameter_type_index, available_registers.gp_registers); + + const parameter_abi = if (available_registers.sse_registers < parameter_classification.needed_registers.sse_registers or available_registers.gp_registers < parameter_classification.needed_registers.gp_registers) b: { + break :b indirect_result(unit, context, parameter_type_index, available_registers.gp_registers); + } else b: { + available_registers.gp_registers -= parameter_classification.needed_registers.gp_registers; + available_registers.sse_registers -= parameter_classification.needed_registers.sse_registers; + break :b parameter_classification.abi; + }; + parameter_types_abi.append_with_capacity(parameter_abi); + } + + function_prototype.abi.return_type_abi = return_abi; + function_prototype.abi.parameter_types_abi = parameter_types_abi.slice(); + } + + const Class_SystemVx86_64 = enum { + no_class, + memory, + integer, + sse, + sseup, + + fn merge(accumulator: Class_SystemVx86_64, field: Class_SystemVx86_64) Class_SystemVx86_64 { + assert(accumulator != .memory); + if (accumulator == field) { + return accumulator; + } else { + var a = accumulator; + var f = field; + if (@intFromEnum(accumulator) > @intFromEnum(field)) { + a = field; + f = accumulator; + } + + return switch (a) { + .no_class => f, + .memory => .memory, + .integer => .integer, + .sse, .sseup => .sse, + }; + } + } + }; + + fn classify_systemv_x86_64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, base_offset: u64) [2]Class_SystemVx86_64 { + var result: [2]Class_SystemVx86_64 = undefined; + const is_memory = base_offset >= 8; + const current_index = @intFromBool(is_memory); + const not_current_index = @intFromBool(!is_memory); + assert(current_index != not_current_index); + result[current_index] = .memory; + result[not_current_index] = .no_class; + + const ty = unit.types.get(type_index); + switch (ty.*) { + .void, .noreturn => result[current_index] = .no_class, + .pointer => result[current_index] = .integer, + .integer => |*integer| switch (type_index) { + .u8, + .u16, + .u32, + .u64, + .usize, + .s8, + .s16, + .s32, + .s64, + .ssize, + .bool, + => result[current_index] = .integer, + else => switch (integer.kind) { + .comptime_int => unreachable, + else => return builder.classify_systemv_x86_64(unit, context, unit.getIntegerType(context, .{ + .bit_count = integer.bit_count, + .signedness = integer.signedness, + .kind = .materialized_int, + }) catch unreachable, base_offset), + }, + }, + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| { + const size = unit.types.get(type_index).getAbiSize(unit); + const alignment = unit.types.get(type_index).getAbiAlignment(unit); + if (size <= 64) { + const has_variable_array = false; + if (!has_variable_array) { + result[current_index] = .no_class; + const is_union = false; + + var member_offset: u32 = 0; + for (struct_type.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + const field_type = unit.types.get(field.type); + const offset = base_offset + member_offset; + const member_size = field_type.getAbiSize(unit); + const member_alignment = field_type.getAbiAlignment(unit); + member_offset = @intCast(data_structures.align_forward(member_offset + member_size, alignment)); + // TODO: + const native_vector_size = 16; + if (size > 16 and ((!is_union and size != member_size) or size > native_vector_size)) { + result[0] = .memory; + const r = classify_post_merge(size, result); + return r; + } + + if (offset % member_alignment != 0) { + result[0] = .memory; + const r = classify_post_merge(size, result); + return r; + } + + const member_classes = builder.classify_systemv_x86_64(unit, context, field.type, offset); + for (&result, member_classes) |*r, m| { + const merge_result = r.merge(m); + r.* = merge_result; + } + + if (result[0] == .memory or result[1] == .memory) break; + } + + result = classify_post_merge(size, result); + } + } + }, + else => |t| @panic(@tagName(t)), + }, + .array => |array| { + const element_type = unit.types.get(array.type); + const element_size = element_type.getAbiSize(unit); + const element_alignment = element_type.getAbiAlignment(unit); + const array_size = ty.getAbiSize(unit); + + if (array_size <= 64) { + if (base_offset % element_alignment == 0) { + result[current_index] = .no_class; + + const vector_size = 16; + if (array_size > 16 and (array_size != element_size or array_size > vector_size)) { + unreachable; + } else { + var offset = base_offset; + + for (0..array.count) |_| { + const element_classes = builder.classify_systemv_x86_64(unit, context, array.type, offset); + offset += element_size; + const merge_result = [2]Class_SystemVx86_64{Class_SystemVx86_64.merge(result[0], element_classes[0]), Class_SystemVx86_64.merge(result[1], element_classes[1])}; + result = merge_result; + if (result[0] == .memory or result[1] == .memory) { + break; + } + } + + const final_result = classify_post_merge(array_size, result); + assert(final_result[1] != .sseup or final_result[0] != .sse); + result = final_result; + } + } else { + unreachable; + } + } else { + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + } + + return result; + } + + fn classify_post_merge(size: u64, classes: [2]Class_SystemVx86_64) [2]Class_SystemVx86_64 { + if (classes[1] == .memory) { + return .{ .memory, .memory }; + } else if (size > 16 and (classes[0] != .sse or classes[1] != .sseup)) { + return .{ .memory, classes[1] }; + } else if (classes[1] == .sseup and classes[0] != .sse and classes[0] != .sseup) { + return .{ classes[0], .sse }; + } else { + return classes; + } + } + + const Member = struct { + type: Type.Index, + offset: u32, + }; + + fn get_member_at_offset(unit: *Unit, struct_type_index: Type.Index, struct_type_descriptor: *Struct.Descriptor, offset: u32) ?Member { + const struct_type = unit.types.get(struct_type_index); + const struct_size = struct_type.getAbiSize(unit); + const struct_alignment = struct_type.getAbiAlignment(unit); + if (struct_size <= offset) return null; + var offset_it: u32 = 0; + var last_match: ?Member = null; + + for (struct_type_descriptor.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + if (offset_it > offset) break; + last_match = .{ + .type = field.type, + .offset = offset_it, + }; + offset_it = @intCast(data_structures.align_forward(offset_it + unit.types.get(field.type).getAbiSize(unit), struct_alignment)); + } + + assert(last_match != null); + return last_match; + } + + fn contains_no_user_data(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, start: u32, end: u32) bool { + const ty = unit.types.get(type_index); + const size = ty.getAbiSize(unit); + return if (size <= start) true else switch (ty.*) { + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| { + var offset: u32 = 0; + + for (struct_type.fields.slice()) |field_index| { + const field = unit.struct_fields.get(field_index); + if (offset >= end) break; + const field_type = unit.types.get(field.type); + const field_start = if (offset < start) start - offset else 0; + if (!builder.contains_no_user_data(unit, context, field.type, field_start, end - offset)) return false; + offset += field_type.getAbiSize(unit); + } + + return true; + }, + else => |t| @panic(@tagName(t)), + }, + .array => |array| { + const element_type = unit.types.get(array.type); + const element_size = element_type.getAbiSize(unit); + + for (0..array.count) |i| { + const offset: u32 = @intCast(i * element_size); + if (offset >= end) break; + const element_start = if (offset < start) start - offset else 0; + if (!builder.contains_no_user_data(unit, context, array.type, element_start, end - offset)) return false; + } + + return true; + }, + else => false, + }; + } + + fn get_int_type_at_offset_system_v_x86_64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, offset: u32, source_type_index: Type.Index, source_offset: u32) Type.Index { + const ty = unit.types.get(type_index); + switch (ty.*) { + .pointer => return if (offset == 0) type_index else unreachable, + .integer => |integer| switch (type_index) { + .u64, .s64, .usize, .ssize => return type_index, + .bool, .u8, .u16, .u32, .s8, .s16, .s32 => { + if (offset != 0) unreachable; + const start = source_offset + ty.getAbiSize(unit); + const end = source_offset + 8; + if (builder.contains_no_user_data(unit, context, source_type_index, start, end)) { + return type_index; + } + }, + else => return builder.get_int_type_at_offset_system_v_x86_64(unit, context, unit.getIntegerType(context, .{ + .bit_count = integer.bit_count, + .signedness = integer.signedness, + .kind = .materialized_int, + }) catch unreachable, offset, source_type_index, source_offset), + }, + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*struct_type| { + if (get_member_at_offset(unit, type_index, struct_type, offset)) |member| { + return builder.get_int_type_at_offset_system_v_x86_64(unit, context, member.type, offset - member.offset, source_type_index, source_offset); + } + unreachable; + }, + else => |t| @panic(@tagName(t)), + }, + .array => |array| { + const element_type = unit.types.get(array.type); + const element_size = element_type.getAbiSize(unit); + const element_offset = (offset / element_size) * element_size; + return builder.get_int_type_at_offset_system_v_x86_64(unit, context, array.type, offset - element_offset, source_type_index, source_offset); + }, + else => |t| @panic(@tagName(t)), + } + + const source_type = unit.types.get(source_type_index); + const source_size = source_type.getAbiSize(unit); + if (source_size - source_offset > 8) { + return .u64; + } else { + const byte_count: u16 = @intCast(source_size - source_offset); + const bit_count = byte_count * 8; + const integer_type = unit.getIntegerType(context, .{ + .bit_count = bit_count, + .kind = .materialized_int, + .signedness = .unsigned, // TODO + }) catch unreachable; + return integer_type; + } + } + + const RegisterAbiX86_64 = struct { + abi: Function.AbiInfo, + needed_registers: SystemV_x86_64_Registers, + }; + + fn classify_argument_type_systemv_x86_64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index, free_gp_registers: u32) RegisterAbiX86_64 { + const type_classes = builder.classify_systemv_x86_64(unit, context, type_index, 0); + assert(type_classes[1] != .memory or type_classes[0] == .memory); + assert(type_classes[1] != .sseup or type_classes[0] == .sse); + + var needed_registers = SystemV_x86_64_Registers{ + .gp_registers = 0, + .sse_registers = 0, + }; + + const result_type = switch (type_classes[0]) { + .integer => b: { + needed_registers.gp_registers += 1; + const result_type = builder.get_int_type_at_offset_system_v_x86_64(unit, context, type_index, 0, type_index, 0); + if (type_classes[1] == .no_class and unit.types.get(type_index).getBitSize(unit) < 32) { + const signed = unit.types.get(type_index).integer.signedness == .unsigned; + return .{ + .abi = .{ + .kind = .{ + .direct_coerce = type_index, + }, + .attributes = .{ + .sign_extend = signed, + .zero_extend = !signed, + }, + }, + .needed_registers = needed_registers, + }; + } else { + break :b result_type; + } + }, + .memory => return .{ + .abi = indirect_result(unit, context, type_index, free_gp_registers), + .needed_registers = needed_registers, + }, + else => |t| @panic(@tagName(t)), + }; + + const high_part: Type.Index = switch (type_classes[1]) { + .no_class, .memory => .null, + .integer => b: { + assert(type_classes[0] != .no_class); + needed_registers.gp_registers += 1; + const high_part = builder.get_int_type_at_offset_system_v_x86_64(unit, context, type_index, 8, type_index, 8); + break :b high_part; + }, + else => |t| @panic(@tagName(t)), + }; + + if (high_part != .null) { + return .{ + .abi = get_argument_pair(unit, .{ result_type, high_part }), + .needed_registers = needed_registers, + }; + } else { + if (result_type != .null) { + if (type_index == result_type) { + return .{ + .abi = .{ + .kind = .direct, + }, + .needed_registers = needed_registers, + }; + } else { + return .{ + .abi = .{ + .kind = .{ + .direct_coerce = result_type, + }, + }, + .needed_registers = needed_registers, + }; + } + } else { + unreachable; + } + unreachable; + } + } + + fn classify_return_type_systemv_x86_64(builder: *Builder, unit: *Unit, context: *const Context, type_index: Type.Index) Function.AbiInfo { + const type_classes = builder.classify_systemv_x86_64(unit, context, type_index, 0); + assert(type_classes[1] != .memory or type_classes[0] == .memory); + assert(type_classes[1] != .sseup or type_classes[0] == .sse); + + const result_type: Type.Index = switch (type_classes[0]) { + .no_class => switch (type_classes[1]) { + .no_class => return .{ + .kind = .ignore, + }, + else => |t| @panic(@tagName(t)), + }, + .integer => b: { + const result_type = builder.get_int_type_at_offset_system_v_x86_64(unit, context, type_index, 0, type_index, 0); + if (type_classes[1] == .no_class and unit.types.get(type_index).getAbiSize(unit) < 32) { + const ty = unit.types.get(result_type); + const signed = ty.integer.signedness == .signed; + return .{ + .kind = .{ + .direct_coerce = result_type, + }, + .attributes = .{ + .sign_extend = signed, + .zero_extend = !signed, + }, + }; + } + break :b result_type; + }, + .memory => return indirect_return_result(unit, context, type_index), + else => |t| @panic(@tagName(t)), + }; + + const high_part: Type.Index = switch (type_classes[1]) { + .integer => b: { + assert(type_classes[0] != .no_class); + const high_part = builder.get_int_type_at_offset_system_v_x86_64(unit, context, type_index, 8, type_index, 8); + break :b high_part; + }, + else => |t| @panic(@tagName(t)), + }; + + if (high_part != .null) { + return get_argument_pair(unit, .{ result_type, high_part }); + } else { + unreachable; + } + } + + fn get_argument_pair(unit: *Unit, types: [2]Type.Index) Function.AbiInfo { + const low_size = unit.types.get(types[0]).getAbiSize(unit); + const high_alignment = unit.types.get(types[1]).getAbiAlignment(unit); + const high_start = data_structures.align_forward(low_size, high_alignment); + assert(high_start == 8); + return .{ + .kind = .{ + .direct_pair = types, + }, + }; + } + + const SystemV_x86_64_Registers = struct { + gp_registers: u32, + sse_registers: u32, + }; + + fn indirect_result(unit: *Unit, context: *const Context, type_index: Type.Index, free_gp_registers: u32) Function.AbiInfo { + const ty = unit.types.get(type_index); + const is_illegal_vector = false; + if (!ty.is_aggregate() and !is_illegal_vector) { + if (ty.* == .integer and ty.integer.bit_count < 32) { + unreachable; + } else { + return .{ + .kind = .direct, + }; + } + } else { + const alignment = ty.getAbiAlignment(unit); + if (free_gp_registers == 0) { + const size = ty.getAbiSize(unit); + if (alignment <= 8 and size <= 8) { + unreachable; + } + } + + const pointer_type = unit.getPointerType(context, .{ + .type = type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }) catch unreachable; + + if (alignment < 8) { + return .{ + .kind = .{ + .indirect = .{ + .type = type_index, + .pointer = pointer_type, + .alignment = 8, + }, + }, + .attributes = .{ + .realign = true, + .by_value = true, + }, + }; + } else { + return .{ + .kind = .{ + .indirect = .{ + .type = type_index, + .pointer = pointer_type, + .alignment = alignment, + }, + }, + .attributes = .{ + .by_value = true, + }, + }; + } + } + } + + fn indirect_return_result(unit: *Unit, context: *const Context, type_index: Type.Index) Function.AbiInfo { + const ty = unit.types.get(type_index); + if (ty.is_aggregate()) { + const pointer_type = unit.getPointerType(context, .{ + .type = type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }) catch unreachable; + return .{ + .kind = .{ + .indirect = .{ + .type = type_index, + .pointer = pointer_type, + .alignment = ty.getAbiAlignment(unit), + }, + }, + }; + } else { + unreachable; + } + } + fn resolveContainerType(builder: *Builder, unit: *Unit, context: *const Context, container_node_index: Node.Index, container_type: ContainerType, maybe_global: ?*Debug.Declaration.Global) !Type.Index { const current_basic_block = builder.current_basic_block; defer builder.current_basic_block = current_basic_block; @@ -6381,6 +7107,7 @@ pub const Builder = struct { array_list.append_with_capacity(member_index); } + var export_declarations = UnpinnedArray(*Debug.Declaration.Global){}; if (count.declarations > 0) { for (declaration_nodes.slice()) |declaration_node_index| { const declaration_node = unit.getNode(declaration_node_index); @@ -6467,6 +7194,9 @@ pub const Builder = struct { const global_declaration = unit.global_declarations.get(global_declaration_index); try builder.current_scope.declarations.put_no_clobber(context.my_allocator, identifier_hash, &global_declaration.declaration); + if (attributes.contains(.@"export")) { + try export_declarations.append(context.my_allocator, global_declaration); + } }, else => unreachable, } @@ -6516,7 +7246,7 @@ pub const Builder = struct { else => b: { const enum_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = integer_type, - }, .{}, field_node.left, null); + }, .{}, field_node.left, null, .right); assert(enum_value.comptime_int.signedness == .unsigned); break :b enum_value.comptime_int.value; }, @@ -6537,7 +7267,7 @@ pub const Builder = struct { const field_type = try builder.resolveType(unit, context, field_node.left); const field_default_value: ?V.Comptime = switch (field_node.right) { .null => null, - else => |default_value_node_index| try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = field_type }, .{}, default_value_node_index, null), + else => |default_value_node_index| try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = field_type }, .{}, default_value_node_index, null, .right), }; const struct_field = try unit.struct_fields.append(context.my_allocator, .{ @@ -6555,7 +7285,7 @@ pub const Builder = struct { const field_type = try builder.resolveType(unit, context, field_node.left); const field_default_value: ?V.Comptime = switch (field_node.right) { .null => null, - else => |default_value_node_index| try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = field_type }, .{}, default_value_node_index, null), + else => |default_value_node_index| try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = field_type }, .{}, default_value_node_index, null, .right), }; const struct_field = try unit.struct_fields.append(context.my_allocator, .{ @@ -6593,28 +7323,37 @@ pub const Builder = struct { } if (unit.descriptor.is_test and count.test_declarations > 0 and unit.main_package.? == unit.files.get(builder.current_file).package) { + const function_type = if (unit.test_function_type != .null) unit.test_function_type else b: { + const return_type = try builder.getErrorUnionType(unit, context, .{ + .@"error" = unit.all_errors, + .type = .void, + }); + + // TODO: make test function prototypes unique + const function_prototype_index = try unit.function_prototypes.append(context.my_allocator, .{ + .argument_types = &.{}, + .return_type = return_type, + .abi = .{ + .return_type = return_type, + }, + .attributes = .{ + .naked = false, + }, + .calling_convention = .auto, + }); + const function_type = try unit.types.append(context.my_allocator, .{ + .function = function_prototype_index, + }); + unit.test_function_type = function_type; + + break :b function_type; + }; + for (test_declarations.slice()) |test_declaration_node_index| { const test_node = unit.getNode(test_declaration_node_index); assert(test_node.id == .test_declaration); - const test_block = unit.getNode(test_node.left); - assert(test_block.id == .block); - - const new_current_basic_block = builder.current_basic_block; - defer builder.current_basic_block = new_current_basic_block; - builder.current_basic_block = .null; - - const old_exit_blocks = builder.exit_blocks; - defer builder.exit_blocks = old_exit_blocks; - builder.exit_blocks = .{}; - - const old_phi_node = builder.return_phi; - defer builder.return_phi = old_phi_node; - builder.return_phi = .null; - - const old_return_block = builder.return_block; - defer builder.return_block = old_return_block; - builder.return_block = .null; + const function_definition_index = try builder.resolveFunctionDefinition(unit, context, function_type, test_declaration_node_index, test_node.left, .null); const test_name_global = if (test_node.right != .null) b: { const test_name_node = unit.getNode(test_node.right); @@ -6626,121 +7365,6 @@ pub const Builder = struct { break :b anon_global; }; - const error_union = try builder.getErrorUnionType(unit, context, .{ - .@"error" = unit.all_errors, - .type = .void, - }); - - const return_type = error_union; - - // TODO: make test function prototypes unique - const function_prototype_index = try unit.function_prototypes.append(context.my_allocator, .{ - .argument_types = &.{}, - .return_type = return_type, - .attributes = .{ - .naked = false, - }, - .calling_convention = .auto, - }); - const function_prototype = unit.function_prototypes.get(function_prototype_index); - const function_type = try unit.types.append(context.my_allocator, .{ - .function = function_prototype_index, - }); - builder.current_function = try unit.function_definitions.append(context.my_allocator, .{ - .scope = .{ - .scope = Debug.Scope{ - .line = token_debug_info.line, - .column = token_debug_info.column, - .kind = .function, - .local = true, - .level = builder.current_scope.level + 1, - .file = builder.current_file, - }, - }, - .type = function_type, - .body = undefined, - }); - const function = unit.function_definitions.get(builder.current_function); - - builder.last_check_point = .{}; - assert(builder.current_scope.kind == .file_container or builder.current_scope.kind == .file or builder.current_scope.kind == .container); - try builder.pushScope(unit, context, &function.scope.scope); - defer builder.popScope(unit, context) catch unreachable; - - const entry_basic_block = try builder.newBasicBlock(unit, context); - builder.current_basic_block = entry_basic_block; - defer builder.current_basic_block = .null; - - try builder.insertDebugCheckPoint(unit, context, test_block.token); - function.body = try builder.resolveBlock(unit, context, test_node.left); - - if (builder.return_block == .null) { - const cbb = unit.basic_blocks.get(builder.current_basic_block); - - if (!cbb.terminated) { - switch (function_prototype.attributes.naked) { - true => { - assert(return_type == .noreturn); - unreachable; - //try builder.buildTrap(unit, context); - }, - false => switch (return_type) { - .void => { - try builder.buildRet(unit, context, .{ - .value = .{ - .@"comptime" = .void, - }, - .type = .void, - }); - }, - .noreturn => { - try builder.buildTrap(unit, context); - }, - else => switch (unit.types.get(return_type).*) { - .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { - .error_union => |return_error_union| { - if (return_error_union.type == .void) { - const undef = V{ - .value = .{ .@"comptime" = .undefined }, - .type = return_type, - }; - const insert_value = try unit.instructions.append(context.my_allocator, .{ - .insert_value = .{ - .expression = undef, - .index = 1, - .new_value = .{ - .value = .{ - .@"comptime" = .{ - .bool = false, - }, - }, - .type = .bool, - }, - }, - }); - try builder.appendInstruction(unit, context, insert_value); - - try builder.buildRet(unit, context, .{ - .value = .{ - .runtime = insert_value, - }, - .type = return_type, - }); - } else if (return_error_union.type == .noreturn) { - unreachable; - } else { - unreachable; - } - }, - else => |t| @panic(@tagName(t)), - }, - else => |t| @panic(@tagName(t)), - }, - }, - } - } - } - const name_hash = test_name_global.initial_value.string_literal; const test_global_index = try unit.global_declarations.append(context.my_allocator, .{ @@ -6754,23 +7378,43 @@ pub const Builder = struct { .kind = .global, }, .initial_value = .{ - .function_definition = builder.current_function, + .function_definition = function_definition_index, }, .type_node_index = .null, .attributes = .{}, }); + const test_global = unit.global_declarations.get(test_global_index); + try scope.scope.declarations.put_no_clobber(context.my_allocator, name_hash, &test_global.declaration); try unit.test_functions.put_no_clobber(context.my_allocator, test_name_global, test_global); - try unit.code_to_emit.put_no_clobber(context.my_allocator, builder.current_function, test_global); + try unit.code_to_emit.put_no_clobber(context.my_allocator, function_definition_index, test_global); + } + } + + // Force analysis of exports + if (export_declarations.length > 0) { + for (export_declarations.slice()) |export_declaration| { + const name = unit.getIdentifier(export_declaration.declaration.name); + _ = name; + //if (byte_equal(name, "nat_big_struct_both")) @breakpoint(); + const result = try builder.referenceGlobalDeclaration(unit, context, &scope.scope, &export_declaration.declaration, .{}); + assert(result == export_declaration); } } return type_index; } + fn emitMemcpy(builder: *Builder, unit: *Unit, context: *const Context, arguments: Instruction.Memcpy) !void { + const memcpy = try unit.instructions.append(context.my_allocator, .{ + .memcpy = arguments, + }); + try builder.appendInstruction(unit, context, memcpy); + } + fn emitIntegerCompare(builder: *Builder, unit: *Unit, context: *const Context, left_value: V, right_value: V, integer: Type.Integer, compare_node_id: Node.Id) anyerror!V { assert(left_value.type == right_value.type); const compare = try unit.instructions.append(context.my_allocator, .{ @@ -6810,13 +7454,863 @@ pub const Builder = struct { }; } + fn resolveFunctionDefinition(builder: *Builder, unit: *Unit, context: *const Context, function_type_index: Type.Index, function_node_index: Node.Index, body_node_index: Node.Index, argument_list_node_index: Node.Index) !Function.Definition.Index { + const current_basic_block = builder.current_basic_block; + defer builder.current_basic_block = current_basic_block; + builder.current_basic_block = .null; + + const old_exit_blocks = builder.exit_blocks; + defer builder.exit_blocks = old_exit_blocks; + builder.exit_blocks = .{}; + + const old_phi_node = builder.return_phi; + defer builder.return_phi = old_phi_node; + builder.return_phi = .null; + + const old_return_block = builder.return_block; + defer builder.return_block = old_return_block; + builder.return_block = .null; + + const function_node = unit.getNode(function_node_index); + const token_debug_info = builder.getTokenDebugInfo(unit, function_node.token); + const old_function = builder.current_function; + builder.current_function = try unit.function_definitions.append(context.my_allocator, .{ + .type = function_type_index, + .body = .null, + .scope = .{ + .scope = Debug.Scope{ + .line = token_debug_info.line, + .column = token_debug_info.column, + .kind = .function, + .local = true, + .level = builder.current_scope.level + 1, + .file = builder.current_file, + }, + }, + }); + + defer builder.current_function = old_function; + + const function = unit.function_definitions.get(builder.current_function); + + builder.last_check_point = .{}; + assert(builder.current_scope.kind == .file_container or builder.current_scope.kind == .file or builder.current_scope.kind == .container); + try builder.pushScope(unit, context, &function.scope.scope); + defer builder.popScope(unit, context) catch unreachable; + + const entry_basic_block = try builder.newBasicBlock(unit, context); + builder.current_basic_block = entry_basic_block; + defer builder.current_basic_block = .null; + + const body_node = unit.getNode(body_node_index); + try builder.insertDebugCheckPoint(unit, context, body_node.token); + + const function_prototype_index = unit.types.get(function_type_index).function; + const function_prototype = unit.function_prototypes.get(function_prototype_index); + + if (function_prototype.abi.return_type_abi.kind == .indirect) { + const return_pointer_argument = try unit.instructions.append(context.my_allocator, .{ + .abi_argument = 0, + }); + try builder.appendInstruction(unit, context, return_pointer_argument); + function.return_pointer = return_pointer_argument; + } + + // Get argument declarations into scope + if (argument_list_node_index != .null) { + const argument_node_list = unit.getNodeList(argument_list_node_index); + assert(argument_node_list.len == function_prototype.argument_types.len); + const argument_types = function_prototype.argument_types; + + for (argument_node_list, argument_types, function_prototype.abi.parameter_types_abi, 0..) |argument_node_index, argument_type_index, argument_abi, i| { + const argument_node = unit.getNode(argument_node_index); + assert(argument_node.id == .argument_declaration); + + const argument_name = switch (unit.getTokenId(argument_node.token)) { + .identifier => b: { + const argument_name = unit.getExpectedTokenBytes(argument_node.token, .identifier); + + break :b argument_name; + }, + .discard => b: { + var buffer: [65]u8 = undefined; + const formatted_int = format_int(&buffer, i, 10, false); + break :b try std.mem.concat(context.allocator, u8, &.{ "_anon_arg_", formatted_int }); + }, + else => |t| @panic(@tagName(t)), + }; + const argument_name_hash = try unit.processIdentifier(context, argument_name); + const look_in_parent_scopes = true; + if (builder.current_scope.lookupDeclaration(argument_name_hash, look_in_parent_scopes)) |_| { + @panic("Symbol already in scope"); + // std.debug.panic("Symbol with name '{s}' already declarared on scope", .{argument_name}); + } + + const argument_token_debug_info = builder.getTokenDebugInfo(unit, argument_node.token); + const argument_declaration_index = try unit.argument_declarations.append(context.my_allocator, .{ + .declaration = .{ + .scope = builder.current_scope, + .name = argument_name_hash, + .type = argument_type_index, + .mutability = .@"const", + .line = argument_token_debug_info.line, + .column = argument_token_debug_info.column, + .kind = .argument, + }, + .index = @intCast(i), + }); + comptime assert(@TypeOf(argument_declaration_index) == Debug.Declaration.Argument.Index); + const argument = unit.argument_declarations.get(argument_declaration_index); + + try builder.current_scope.declarations.put_no_clobber(context.my_allocator, argument_name_hash, &argument.declaration); + + var argument_abi_instructions: [12]Instruction.Index = undefined; + const argument_abi_count = argument_abi.indices[1] - argument_abi.indices[0]; + for (0..argument_abi_count) |argument_index| { + const argument_instruction = try unit.instructions.append(context.my_allocator, .{ + .abi_argument = @intCast(argument_abi.indices[0] + argument_index), + }); + + try builder.appendInstruction(unit, context, argument_instruction); + + argument_abi_instructions[argument_index] = argument_instruction; + } + + const argument_type = unit.types.get(argument_type_index); + + const LowerKind = union(enum) { + direct, + direct_pair: [2]Type.Index, + direct_coerce: Type.Index, + indirect, + }; + + const lower_kind: LowerKind = switch (argument_abi.kind) { + .direct => .direct, + .direct_coerce => |coerced_type_index| if (argument_type_index == coerced_type_index) .direct else .{ + .direct_coerce = coerced_type_index, + }, + .direct_pair => |pair| .{ + .direct_pair = pair, + }, + .indirect => .indirect, + else => |t| @panic(@tagName(t)), + }; + + const stack = switch (lower_kind) { + .direct => b: { + assert(argument_abi_count == 1); + const stack = try builder.createStackVariable(unit, context, argument_type_index, null); + + const pointer_type = try unit.getPointerType(context, .{ + .type = argument_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = .{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }, + .source = .{ + .value = .{ + .runtime = argument_abi_instructions[0], + }, + .type = argument_type_index, + }, + }, + }); + + try builder.appendInstruction(unit, context, store); + + break :b stack; + }, + .direct_pair => |pair| b: { + assert(argument_abi_count == 2); + const types = [2]*Type{ unit.types.get(pair[0]), unit.types.get(pair[1]) }; + assert(types[0].* == .integer); + assert(types[1].* == .integer); + const alignments = [2]u32{ types[0].getAbiAlignment(unit), types[1].getAbiAlignment(unit) }; + const sizes = [2]u32{ types[0].getAbiSize(unit), types[1].getAbiSize(unit) }; + const alignment = @max(alignments[0], alignments[1]); + _ = alignment; // autofix + const high_aligned_size: u32 = @intCast(data_structures.align_forward(sizes[1], alignments[1])); + _ = high_aligned_size; // autofix + const high_offset: u32 = @intCast(data_structures.align_forward(sizes[0], alignments[1])); + assert(high_offset + sizes[1] <= argument_type.getAbiSize(unit)); + const stack = try builder.createStackVariable(unit, context, argument_type_index, null); + + // const pointer_type = try unit.getPointerType(context, .{ + // .type = argument_type_index, + // .termination = .none, + // .mutability = .@"var", + // .many = false, + // .nullable = false, + // }); + // _ = pointer_type; // autofix + + const pointer_types = [2]Type.Index{ + try unit.getPointerType(context, .{ + .type = pair[0], + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }), + try unit.getPointerType(context, .{ + .type = pair[0], + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }), + }; + + var destination = V{ + .type = pointer_types[0], + .value = .{ + .runtime = stack, + }, + }; + + var source = V{ + .value = .{ + .runtime = argument_abi_instructions[0], + }, + .type = pair[0], + }; + const first_store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = destination, + .source = source, + }, + }); + try builder.appendInstruction(unit, context, first_store); + + // TODO: should we use this? + // const offset = @divExact(high_offset, high_aligned_size); + // _ = offset; // autofix + + const gep = try unit.instructions.append(context.my_allocator, .{ + .get_element_pointer = .{ + .pointer = stack, + .base_type = pair[0], + .is_struct = false, + .index = .{ + .value = .{ + .@"comptime" = .{ + .constant_int = .{ + .value = 1, + }, + }, + }, + .type = .usize, + }, + }, + }); + try builder.appendInstruction(unit, context, gep); + + destination = .{ + .value = .{ + .runtime = gep, + }, + .type = pointer_types[1], + }; + + source = .{ + .value = .{ + .runtime = argument_abi_instructions[1], + }, + .type = pair[1], + }; + + const second_store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = destination, + .source = source, + }, + }); + try builder.appendInstruction(unit, context, second_store); + + break :b stack; + }, + .indirect => b: { + assert(argument_abi_count == 1); + break :b argument_abi_instructions[0]; + }, + .direct_coerce => |coerced_type_index| b: { + assert(coerced_type_index != argument_type_index); + assert(argument_abi_count == 1); + + const argument_size = argument_type.getAbiSize(unit); + const argument_alloca = try builder.createStackVariable(unit, context, argument_type_index, null); + const coerced_type = unit.types.get(coerced_type_index); + const coerced_size = coerced_type.getAbiSize(unit); + const argument_pointer_type = try unit.getPointerType(context, .{ + .type = argument_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + switch (argument_type.*) { + .@"struct" => { + // TODO: + const is_vector = false; + + if (coerced_size <= argument_size and !is_vector) { + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = .{ + .value = .{ + .runtime = argument_alloca, + }, + .type = argument_pointer_type, + }, + .source = .{ + .value = .{ + .runtime = argument_abi_instructions[0], + }, + .type = coerced_type_index, + }, + }, + }); + + try builder.appendInstruction(unit, context, store); + } else { + const coerced_alloca = try builder.createStackVariable(unit, context, coerced_type_index, null); + const coerced_pointer_type = try unit.getPointerType(context, .{ + .type = coerced_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = .{ + .value = .{ + .runtime = coerced_alloca, + }, + .type = coerced_pointer_type, + }, + .source = .{ + .value = .{ + .runtime = argument_abi_instructions[0], + }, + .type = coerced_type_index, + }, + }, + }); + try builder.appendInstruction(unit, context, store); + + try builder.emitMemcpy(unit, context, .{ + .destination = .{ + .value = .{ + .runtime = argument_alloca, + }, + .type = argument_pointer_type, + }, + .source = .{ + .value = .{ + .runtime = coerced_alloca, + }, + .type = coerced_pointer_type, + }, + .destination_alignment = null, + .source_alignment = null, + .size = argument_size, + .is_volatile = false, + }); + } + + break :b argument_alloca; + }, + else => |t| @panic(@tagName(t)), + } + }, + // else => |t| @panic(@tagName(t)), + }; + + try function.scope.argument_map.put_no_clobber(context.my_allocator, argument, stack); + + const debug_declare_argument = try unit.instructions.append(context.my_allocator, .{ + .debug_declare_argument = .{ + .argument = argument, + .stack = stack, + }, + }); + + try builder.appendInstruction(unit, context, debug_declare_argument); + } + } + + if (body_node.id == .block) { + function.body = try builder.resolveBlock(unit, context, body_node_index); + + if (builder.return_phi != .null) { + const old_block = builder.current_basic_block; + builder.current_basic_block = builder.return_block; + + try builder.appendInstruction(unit, context, builder.return_phi); + try builder.buildRet(unit, context, .{ + .value = .{ + .runtime = builder.return_phi, + }, + .type = function_prototype.return_type, + }); + + builder.current_basic_block = old_block; + } + + const cbb = unit.basic_blocks.get(builder.current_basic_block); + const return_type = function_prototype.return_type; + + if (!cbb.terminated and (cbb.instructions.length > 0 or cbb.predecessors.length > 0)) { + if (builder.return_block == .null) { + switch (unit.types.get(return_type).*) { + .void => try builder.buildRet(unit, context, .{ + .value = .{ + .@"comptime" = .void, + }, + .type = .void, + }), + .noreturn => try builder.buildTrap(unit, context), + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .error_union => |error_union| { + assert(function_prototype.calling_convention == .auto); + switch (error_union.type) { + .void => { + assert(error_union.abi == error_union.union_for_type); + const undefined_value = V{ + .value = .{ + .@"comptime" = .undefined, + }, + .type = return_type, + }; + const insert = try unit.instructions.append(context.my_allocator, .{ + .insert_value = .{ + .expression = undefined_value, + .index = 1, + .new_value = .{ + .value = .{ + .@"comptime" = .{ + .bool = false, + }, + }, + .type = .bool, + }, + }, + }); + try builder.appendInstruction(unit, context, insert); + + try builder.buildRet(unit, context, .{ + .value = .{ + .runtime = insert, + }, + .type = return_type, + }); + }, + else => unreachable, + } + }, + else => |t| @panic(@tagName(t)), + }, + else => unreachable, + } + } else { + assert(function_prototype.calling_convention == .auto); + assert(builder.return_phi != .null); + assert(builder.return_block != builder.current_basic_block); + + const phi = &unit.instructions.get(builder.return_phi).phi; + + switch (unit.types.get(return_type).*) { + .void => unreachable, + .noreturn => unreachable, + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .error_union => |error_union| { + if (error_union.type == .void or + // TODO: is this correct? + error_union.type == .noreturn) + { + const return_value = try unit.instructions.append(context.my_allocator, .{ + .insert_value = .{ + .expression = .{ + .value = .{ + .@"comptime" = .undefined, + }, + .type = return_type, + }, + .index = 1, + .new_value = .{ + .value = .{ + .@"comptime" = .{ + .bool = false, + }, + }, + .type = .bool, + }, + }, + }); + try builder.appendInstruction(unit, context, return_value); + + try phi.addIncoming(context, .{ + .value = .{ + .runtime = return_value, + }, + .type = return_type, + }, builder.current_basic_block); + + try builder.jump(unit, context, builder.return_block); + } else { + try unit.dumpFunctionDefinition(builder.current_function); + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + }, + else => { + try unit.dumpFunctionDefinition(builder.current_function); + unreachable; + }, + } + } + } + + const current_function = builder.current_function; + return current_function; + } else { + @panic("Function body is expected to be a block"); + } + } + + /// Last value is used to cache types being analyzed so we dont hit stack overflow + fn resolveComptimeValue(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, global_attributes: Debug.Declaration.Global.Attributes, node_index: Node.Index, maybe_global: ?*Debug.Declaration.Global, side: Side) anyerror!V.Comptime { + const node = unit.getNode(node_index); + switch (node.id) { + .intrinsic => { + const argument_node_list = unit.getNodeList(node.left); + const intrinsic_id: IntrinsicId = @enumFromInt(Node.unwrap(node.right)); + switch (intrinsic_id) { + .import => { + assert(argument_node_list.len == 1); + const file_index = try builder.resolveImport(unit, context, type_expect, argument_node_list); + const file = unit.files.get(file_index); + return .{ + .type = file.type, + }; + }, + .@"error" => { + assert(argument_node_list.len == 1); + // TODO: type + const argument_node = unit.getNode(argument_node_list[0]); + switch (argument_node.id) { + .string_literal => { + const error_message = try unit.fixupStringLiteral(context, argument_node.token); + builder.reportCompileError(unit, context, .{ + .message = error_message, + .node = node_index, + }); + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + }, + .field_access => { + const result = try builder.resolveFieldAccess(unit, context, type_expect, node_index, .right); + return switch (result.value) { + .@"comptime" => |ct| ct, + else => @panic("Expected comptime value, found runtime value"), + }; + }, + .keyword_false, + .keyword_true, + => return .{ + .bool = node.id == .keyword_true, + }, + .function_definition => { + // if (@intFromEnum(node_index) == 2183) @breakpoint(); + const function_prototype_node_index = node.left; + const function_prototype_node = unit.getNode(function_prototype_node_index); + const argument_list_node_index = function_prototype_node.left; + const body_node_index = node.right; + + const function_type_index = try builder.resolveFunctionPrototype(unit, context, function_prototype_node_index, global_attributes); + + const function_definition_index = try builder.resolveFunctionDefinition(unit, context, function_type_index, node_index, body_node_index, argument_list_node_index); + + return .{ + .function_definition = function_definition_index, + }; + }, + .number_literal => switch (std.zig.parseNumberLiteral(unit.getExpectedTokenBytes(node.token, .number_literal))) { + .int => |integer| { + return .{ + .comptime_int = .{ + .value = integer, + .signedness = .unsigned, + }, + }; + }, + else => |t| @panic(@tagName(t)), + }, + .undefined => { + return .undefined; + }, + .enum_type, .struct_type, .bitfield_type => { + const type_index = try builder.resolveContainerType(unit, context, node_index, switch (node.id) { + .enum_type => .@"enum", + .struct_type => .@"struct", + .bitfield_type => .bitfield, + else => unreachable, + }, maybe_global); + return .{ + .type = type_index, + }; + }, + .@"switch" => return try builder.resolveComptimeSwitch(unit, context, type_expect, global_attributes, node_index, maybe_global), + .identifier => { + const identifier = unit.getExpectedTokenBytes(node.token, .identifier); + // const side: Side = switch (type_expect) { + // .none => .left, + // .type => |type_index| switch (unit.types.get(type_index).*) { + // .type => .right, + // else => |t| @panic(@tagName(t)), + // }, + // else => unreachable, + // }; + const resolved_value = try builder.resolveIdentifier(unit, context, type_expect, identifier, global_attributes, side); + return switch (resolved_value.value) { + .@"comptime" => |ct| ct, + .runtime => return error.cannot_evaluate, + else => unreachable, + }; + }, + .signed_integer_type => { + const result = try builder.resolveIntegerType(unit, context, node_index); + return .{ + .type = result, + }; + }, + .compare_greater_equal => { + const left = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null, .right); + const left_type = left.getType(unit); + const right = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = left_type }, .{}, node.right, null, .right); + _ = right; // autofix + unreachable; + }, + .add => { + const left = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null, .right); + const left_type = left.getType(unit); + const right = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = left_type }, .{}, node.right, null, .right); + switch (left) { + .comptime_int => |left_ct_int| { + assert(left_ct_int.signedness == .unsigned); + const left_value = left_ct_int.value; + switch (right) { + .comptime_int => |right_ct_int| { + assert(right_ct_int.signedness == .unsigned); + const right_value = right_ct_int.value; + const result = left_value + right_value; + return .{ + .comptime_int = .{ + .value = result, + .signedness = .unsigned, + }, + }; + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + }, + .empty_container_literal_guess => { + assert(node.left != .null); + assert(node.right != .null); + const container_type = try builder.resolveType(unit, context, node.left); + const node_list = unit.getNodeList(node.right); + assert(node_list.len == 0); + const result = try builder.resolveContainerLiteral(unit, context, node_list, container_type); + return switch (result.value) { + .@"comptime" => |ct| ct, + else => |t| @panic(@tagName(t)), + }; + }, + .anonymous_container_literal => { + assert(node.left == .null); + assert(node.right != .null); + switch (type_expect) { + .type => |type_index| { + const node_list = unit.getNodeList(node.right); + const result = try builder.resolveContainerLiteral(unit, context, node_list, type_index); + return switch (result.value) { + .@"comptime" => |ct| ct, + else => |t| @panic(@tagName(t)), + }; + }, + else => |t| @panic(@tagName(t)), + } + }, + .function_prototype => { + const function_prototype = try builder.resolveFunctionPrototype(unit, context, node_index, global_attributes); + if (global_attributes.contains(.@"extern")) { + return .{ + .function_declaration = function_prototype, + }; + } else { + unreachable; + } + }, + .error_type => { + assert(node.left != .null); + const nodes = unit.getNodeList(node.left); + if (nodes.len == 0) { + unreachable; + } + + const token_debug_info = builder.getTokenDebugInfo(unit, node.token); + const error_type_index = try unit.types.append(context.my_allocator, .{ + .integer = .{ + .signedness = .unsigned, + .bit_count = 32, + .kind = .{ + .@"error" = .{ + .scope = .{ + .scope = .{ + .file = builder.current_file, + .line = token_debug_info.line, + .column = token_debug_info.column, + .kind = .container, + .local = false, + .level = builder.current_scope.level + 1, + .parent = builder.current_scope, + }, + }, + .fields = try UnpinnedArray(Type.Error.Field.Index).initialize_with_capacity(context.my_allocator, @intCast(nodes.len)), + .id = unit.error_count, + }, + }, + }, + }); + unit.error_count += 1; + + const error_type = &unit.types.get(error_type_index).integer.kind.@"error"; + for (nodes, 0..) |field_node_index, index| { + const field_node = unit.getNode(field_node_index); + const identifier = unit.getExpectedTokenBytes(field_node.token, .identifier); + const hash = try unit.processIdentifier(context, identifier); + const error_field_index = try unit.error_fields.append(context.my_allocator, .{ + .name = hash, + .type = error_type_index, + .value = index, + }); + error_type.fields.append_with_capacity(error_field_index); + } + + return .{ + .type = error_type_index, + }; + }, + .dot_literal => { + switch (type_expect) { + .type => |type_index| { + const expected_type = unit.types.get(type_index); + const identifier = unit.getExpectedTokenBytes(Token.addInt(node.token, 1), .identifier); + const hash = try unit.processIdentifier(context, identifier); + switch (expected_type.*) { + .integer => |*integer| switch (integer.kind) { + .@"enum" => |*enum_type| { + for (enum_type.fields.slice()) |field_index| { + const field = unit.enum_fields.get(field_index); + if (field.name == hash) { + return .{ + .enum_value = field_index, + }; + } + } else { + unreachable; + } + }, + .@"error" => |*error_type| { + for (error_type.fields.slice()) |field_index| { + const field = unit.error_fields.get(field_index); + if (field.name == hash) { + return .{ + .error_value = field_index, + }; + } + } else { + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + }, + .address_of => { + assert(node.left != .null); + assert(node.right == .null); + + const appointee = unit.getNode(node.left); + switch (appointee.id) { + .anonymous_empty_literal => switch (type_expect) { + .type => |type_index| switch (unit.types.get(type_index).*) { + .slice => |slice| { + _ = slice; // autofix + var field_list = try UnpinnedArray(V.Comptime).initialize_with_capacity(context.my_allocator, 2); + + field_list.append_with_capacity(.undefined); + field_list.append_with_capacity(V.Comptime{ + .constant_int = .{ + .value = 0, + }, + }); + + const constant_slice = try unit.constant_slices.append(context.my_allocator, .{ + .array = null, + .start = 0, + .end = 0, + .type = type_index, + }); + + return .{ + .constant_slice = constant_slice, + }; + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + } + fn resolveRuntimeValue(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side) anyerror!V { const node = unit.getNode(node_index); const v: V = switch (node.id) { .identifier => block: { const identifier = unit.getExpectedTokenBytes(node.token, .identifier); - const result = try builder.resolveIdentifier(unit, context, type_expect, identifier, side); + const result = try builder.resolveIdentifier(unit, context, type_expect, identifier, .{}, side); break :block result; }, .intrinsic => try builder.resolveIntrinsic(unit, context, type_expect, node_index), @@ -6953,7 +8447,7 @@ pub const Builder = struct { break :block switch (unit.types.get(left_value.type).*) { .integer => |integer| switch (integer.kind) { - .materialized_int => try builder.emitIntegerCompare(unit, context, left_value, right_value, integer, cmp_node_id), + .materialized_int, .bool => try builder.emitIntegerCompare(unit, context, left_value, right_value, integer, cmp_node_id), else => |t| @panic(@tagName(t)), }, .pointer => |pointer| b: { @@ -7357,6 +8851,9 @@ pub const Builder = struct { break :blk nullable_pointer; }, }, + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + else => |t| @panic(@tagName(t)), + }, else => |t| @panic(@tagName(t)), }, else => |t| @panic(@tagName(t)), @@ -7972,6 +9469,23 @@ pub const Builder = struct { .type = type_index, }; }, + .slice_zero_to_no_termination => { + const cast = try unit.instructions.append(context.my_allocator, .{ + .cast = .{ + .id = .slice_zero_to_no_termination, + .value = slice_value, + .type = type_index, + }, + }); + + try builder.appendInstruction(unit, context, cast); + return .{ + .value = .{ + .runtime = cast, + }, + .type = type_index, + }; + }, else => |t| @panic(@tagName(t)), }, else => |t| @panic(@tagName(t)), @@ -8713,7 +10227,6 @@ pub const Builder = struct { .materialized_int => { assert(integer.signedness == .signed); var v: i64 = @intCast(constant_int.value); - v = -v; v = 0 - v; break :block .{ @@ -8807,7 +10320,7 @@ pub const Builder = struct { .type = .void, }; }, - .@"switch" => try builder.resolveSwitch(unit, context, type_expect, node_index, side), + .@"switch" => try builder.resolveSwitch(unit, context, type_expect, node_index, side, null), .catch_expression => try builder.resolveCatchExpression(unit, context, type_expect, node_index, side), .@"unreachable" => block: { try builder.buildTrap(unit, context); @@ -8819,6 +10332,14 @@ pub const Builder = struct { }; }, .try_expression => try builder.resolveTryExpression(unit, context, type_expect, node_index, side), + .bitfield_type => .{ + .type = try builder.resolveContainerType(unit, context, node_index, switch (node.id) { + .enum_type => .@"enum", + .struct_type => .@"struct", + .bitfield_type => .bitfield, + else => unreachable, + }, unreachable), + }, else => |t| @panic(@tagName(t)), }; @@ -8875,12 +10396,7 @@ pub const Builder = struct { const error_value = if (error_union.union_for_error == error_union.abi) { unreachable; } else err: { - const try_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = value.type, - }, - }); - try builder.appendInstruction(unit, context, try_alloca); + const try_alloca = try builder.createStackVariable(unit, context, value.type, null); const try_store = try unit.instructions.append(context.my_allocator, .{ .store = .{ @@ -9026,12 +10542,7 @@ pub const Builder = struct { }); try builder.appendInstruction(unit, context, final_error_union); - const support_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = error_union.union_for_error, - }, - }); - try builder.appendInstruction(unit, context, support_alloca); + const support_alloca = try builder.createStackVariable(unit, context, error_union.union_for_error, null); const pointer_type = try unit.getPointerType(context, .{ .type = error_union.union_for_error, @@ -9102,12 +10613,7 @@ pub const Builder = struct { .type = error_union.@"error", }; } else err: { - const try_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = value.type, - }, - }); - try builder.appendInstruction(unit, context, try_alloca); + const try_alloca = try builder.createStackVariable(unit, context, value.type, null); const try_store = try unit.instructions.append(context.my_allocator, .{ .store = .{ @@ -9202,18 +10708,7 @@ pub const Builder = struct { const phi_block = try builder.newBasicBlock(unit, context); try phi.addIncoming(context, final_error_union, builder.current_basic_block); - const old_block = builder.current_basic_block; - builder.current_basic_block = phi_block; - - try builder.appendInstruction(unit, context, phi_index); - try builder.buildRet(unit, context, .{ - .value = .{ - .runtime = phi_index, - }, - .type = return_type_index, - }); - - builder.current_basic_block = old_block; + // const old_block = builder.current_basic_block; builder.return_phi = phi_index; builder.return_block = phi_block; @@ -9589,7 +11084,8 @@ pub const Builder = struct { assert(node.right != .null); const left_node = unit.getNode(node.left); - var argument_list = UnpinnedArray(V){}; + var member: ?V = null; + const callable: V = switch (left_node.id) { .field_access => blk: { const right_identifier_node = unit.getNode(left_node.right); @@ -9607,15 +11103,18 @@ pub const Builder = struct { const look_in_parent_scopes = false; if (container_scope.lookupDeclaration(right_identifier_hash, look_in_parent_scopes)) |lookup| { - const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration); + const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}); switch (global.initial_value) { - .function_definition, .function_declaration => break :blk .{ - .value = .{ - .@"comptime" = .{ - .global = global, + .function_definition, .function_declaration => { + const value = V{ + .value = .{ + .@"comptime" = .{ + .global = global, + }, }, - }, - .type = global.declaration.type, + .type = global.declaration.type, + }; + break :blk value; }, else => |t| @panic(@tagName(t)), } @@ -9636,7 +11135,7 @@ pub const Builder = struct { } else { const look_in_parent_scopes = false; if (struct_type.scope.scope.lookupDeclaration(right_identifier_hash, look_in_parent_scopes)) |lookup| { - const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration); + const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}); switch (right_symbol.initial_value) { .function_definition => { const function_type_index = right_symbol.declaration.type; @@ -9648,7 +11147,8 @@ pub const Builder = struct { const first_argument_type_index = function_prototype.argument_types[0]; if (first_argument_type_index == field_access_left.type) { - try argument_list.append(context.my_allocator, field_access_left); + member = field_access_left; + // try argument_list.append(context.my_allocator, field_access_left); break :blk V{ .value = .{ .@"comptime" = .{ @@ -9742,7 +11242,7 @@ pub const Builder = struct { } else { const look_in_parent_scopes = false; if (struct_type.scope.scope.lookupDeclaration(right_identifier_hash, look_in_parent_scopes)) |lookup| { - const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration); + const right_symbol = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}); switch (right_symbol.initial_value) { .function_definition => { const function_type_index = right_symbol.declaration.type; @@ -9754,7 +11254,7 @@ pub const Builder = struct { const first_argument_type_index = function_prototype.argument_types[0]; if (first_argument_type_index == field_access_left.type) { - try argument_list.append(context.my_allocator, field_access_left); + member = field_access_left; break :blk V{ .value = .{ .@"comptime" = .{ @@ -9772,12 +11272,12 @@ pub const Builder = struct { }); try builder.appendInstruction(unit, context, load); - try argument_list.append(context.my_allocator, .{ + member = .{ .value = .{ .runtime = load, }, .type = first_argument_type_index, - }); + }; break :blk V{ .value = .{ @@ -9901,7 +11401,7 @@ pub const Builder = struct { }, .identifier => blk: { const identifier = unit.getExpectedTokenBytes(left_node.token, .identifier); - const result = try builder.resolveIdentifier(unit, context, Type.Expect.none, identifier, .left); + const result = try builder.resolveIdentifier(unit, context, Type.Expect.none, identifier, .{}, .left); break :blk switch (result.value) { .@"comptime" => |ct| switch (ct) { .global => |global| switch (global.initial_value) { @@ -9975,14 +11475,49 @@ pub const Builder = struct { const argument_declaration_count = function_prototype.argument_types.len; // Argument list holds already the value of the member value - if (argument_nodes.len + argument_list.length != argument_declaration_count) { + if (argument_nodes.len + @intFromBool(member != null) != argument_declaration_count) { @panic("Argument count mismatch"); } - try argument_list.ensure_capacity(context.my_allocator, @intCast(argument_declaration_count)); + const is_indirect = function_prototype.abi.return_type_abi.kind == .indirect; + const extra_member_count = @as(usize, @intFromBool(is_indirect)) + @intFromBool(member != null); - const argument_offset = argument_list.length; - for (argument_nodes, function_prototype.argument_types[argument_offset..]) |arg_ni, argument_type_index| { + var argument_list = try UnpinnedArray(V).initialize_with_capacity(context.my_allocator, @intCast(argument_declaration_count + extra_member_count)); + + const indirect_return: ?V = switch (function_prototype.abi.return_type_abi.kind) { + .indirect => |indirect| b: { + const indirect_type = unit.types.get(indirect.type); + const indirect_alignment = indirect_type.getAbiAlignment(unit); + if (indirect.alignment <= indirect_alignment) { + const stack = try builder.createStackVariable(unit, context, indirect.type, null); + const v = V{ + .value = .{ + .runtime = stack, + }, + .type = indirect.pointer, + }; + argument_list.append_with_capacity(v); + + break :b v; + } else { + unreachable; + } + }, + else => null, + }; + + if (member) |m| { + const member_argument_index = @intFromBool(is_indirect); + const abi = function_prototype.abi.parameter_types_abi[member_argument_index]; + switch (abi.kind) { + .direct => argument_list.append_with_capacity(m), + else => |t| @panic(@tagName(t)), + } + } + + const argument_offset = @intFromBool(member != null); + //extra_memmber_count + for (argument_nodes, function_prototype.argument_types[argument_offset..], function_prototype.abi.parameter_types_abi[argument_offset..]) |arg_ni, argument_type_index, argument_abi| { const argument_node = unit.getNode(arg_ni); const arg_type_expect = Type.Expect{ .type = argument_type_index, @@ -9992,13 +11527,344 @@ pub const Builder = struct { else => arg_ni, }; const argument_value = try builder.resolveRuntimeValue(unit, context, arg_type_expect, argument_node_index, .right); - argument_list.append_with_capacity(argument_value); - } - for (function_prototype.argument_types, argument_list.slice(), 0..) |argument_type, argument_value, i| { - _ = i; // autofix - if (argument_type != argument_value.type) { - @panic("Type mismatch"); + switch (argument_abi.kind) { + .direct => argument_list.append_with_capacity(argument_value), + .direct_coerce => |coerced_type_index| if (coerced_type_index == argument_value.type) argument_list.append_with_capacity(argument_value) else { + const stack = try builder.createStackVariable(unit, context, argument_value.type, null); + + const pointer_type = try unit.getPointerType(context, .{ + .type = argument_value.type, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + const argument_alloca = V{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }; + + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = argument_alloca, + .source = argument_value, + }, + }); + try builder.appendInstruction(unit, context, store); + + const target_type = unit.types.get(coerced_type_index); + const target_alignment = target_type.getAbiAlignment(unit); + const target_size = target_type.getAbiSize(unit); + // const types = [2]*Type{unit.types.get(pair[0]), unit.types.get(pair[1])}; + const source_type = unit.types.get(argument_value.type); + const source_alignment = source_type.getAbiAlignment(unit); + const source_size = source_type.getAbiSize(unit); + const target_is_scalable_vector_type = false; + const source_is_scalable_vector_type = false; + + if (source_size >= target_size and !source_is_scalable_vector_type and !target_is_scalable_vector_type) { + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = argument_alloca, + .type = coerced_type_index, + }, + }); + try builder.appendInstruction(unit, context, load); + + argument_list.append_with_capacity(V{ + .value = .{ + .runtime = load, + }, + .type = coerced_type_index, + }); + } else { + const alignment = @max(target_alignment, source_alignment); + const temporal = try builder.createStackVariable(unit, context, coerced_type_index, alignment); + const coerced_pointer_type = try unit.getPointerType(context, .{ + .type = coerced_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + const destination = V{ + .value = .{ + .runtime = temporal, + }, + .type = coerced_pointer_type, + }; + try builder.emitMemcpy(unit, context, .{ + .destination = destination, + .source = argument_alloca, + .destination_alignment = alignment, + .source_alignment = source_alignment, + .size = source_size, + .is_volatile = false, + }); + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = destination, + .type = coerced_type_index, + .alignment = alignment, + }, + }); + try builder.appendInstruction(unit, context, load); + + argument_list.append_with_capacity(V{ + .value = .{ + .runtime = load, + }, + .type = coerced_type_index, + }); + } + }, + .direct_pair => |pair| { + const struct_type_index = try unit.getTwoStruct(context, pair); + const pair_struct_type = unit.types.get(struct_type_index); + const are_similar = b: { + if (struct_type_index == argument_type_index) { + break :b true; + } else { + const original_type = unit.types.get(argument_type_index); + switch (original_type.*) { + .@"struct" => |struct_index| switch (unit.structs.get(struct_index).kind) { + .@"struct" => |*original_struct| { + if (original_struct.fields.length == 2) { + for (original_struct.fields.slice(), pair) |field_index, pair_type_index| { + const field = unit.struct_fields.get(field_index); + if (field.type != pair_type_index) break :b false; + } + + break :b true; + } else { + break :b false; + } + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + } + } + }; + + if (are_similar) { + const extract_0 = try unit.instructions.append(context.my_allocator, .{ + .extract_value = .{ + .expression = argument_value, + .index = 0, + }, + }); + try builder.appendInstruction(unit, context, extract_0); + + argument_list.append_with_capacity(.{ + .value = .{ + .runtime = extract_0, + }, + .type = pair[0], + }); + + const extract_1 = try unit.instructions.append(context.my_allocator, .{ + .extract_value = .{ + .expression = argument_value, + .index = 1, + }, + }); + try builder.appendInstruction(unit, context, extract_1); + + argument_list.append_with_capacity(.{ + .value = .{ + .runtime = extract_1, + }, + .type = pair[1], + }); + } else { + const argument_type = unit.types.get(argument_type_index); + const argument_alignment = argument_type.getAbiAlignment(unit); + const target_type = pair_struct_type; + const target_alignment = target_type.getAbiAlignment(unit); + + const alloca_value = if (argument_alignment < target_alignment) b: { + const coerced_alloca = try builder.createStackVariable(unit, context, struct_type_index, null); + const coerced_pointer_type = try unit.getPointerType(context, .{ + .type = struct_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + const coerced_pointer = V{ + .value = .{ + .runtime = coerced_alloca, + }, + .type = coerced_pointer_type, + }; + const coerced_store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = coerced_pointer, + .source = argument_value, + }, + }); + try builder.appendInstruction(unit, context, coerced_store); + + break :b coerced_pointer; + + } else b: { + const pointer_type = try unit.getPointerType(context, .{ + .type = argument_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + const alloca = try builder.createStackVariable(unit, context, argument_type_index, null); + + const argument_alloca = V{ + .value = .{ + .runtime = alloca, + }, + .type = pointer_type, + }; + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = argument_alloca, + .source = argument_value, + }, + }); + try builder.appendInstruction(unit, context, store); + + break :b argument_alloca; + }; + const gep0 = try unit.instructions.append(context.my_allocator, .{ + .get_element_pointer = .{ + .pointer = alloca_value.value.runtime, + .base_type = struct_type_index, + .is_struct = true, + .index = .{ + .value = .{ + .@"comptime" = .{ + .constant_int = .{ + .value = 0, + }, + }, + }, + .type = .u32, + }, + }, + }); + try builder.appendInstruction(unit, context, gep0); + + const load0 = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = .{ + .value = .{ + .runtime = gep0, + }, + .type = try unit.getPointerType(context, .{ + .type = pair[0], + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }), + }, + .type = pair[0], + }, + }); + try builder.appendInstruction(unit, context, load0); + + const gep1 = try unit.instructions.append(context.my_allocator, .{ + .get_element_pointer = .{ + .pointer = alloca_value.value.runtime, + .base_type = struct_type_index, + .is_struct = true, + .index = .{ + .value = .{ + .@"comptime" = .{ + .constant_int = .{ + .value = 1, + }, + }, + }, + .type = .u32, + }, + }, + }); + try builder.appendInstruction(unit, context, gep1); + + const load1 = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = .{ + .value = .{ + .runtime = gep1, + }, + .type = try unit.getPointerType(context, .{ + .type = pair[1], + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }), + }, + .type = pair[1], + }, + }); + try builder.appendInstruction(unit, context, load1); + + + argument_list.append_with_capacity(V{ + .value = .{ + .runtime = load0, + }, + .type = pair[0], + }); + argument_list.append_with_capacity(V{ + .value = .{ + .runtime = load1, + }, + .type = pair[1], + }); + } + }, + .indirect => |indirect| { + const argument_type = unit.types.get(argument_type_index); + const indirect_pointer_type = unit.types.get(indirect.pointer); + assert(argument_type_index == indirect_pointer_type.pointer.type); + assert(indirect.type == argument_type_index); + + const direct = b: { + if (!argument_abi.attributes.by_value) break :b false; + switch (argument_type.*) { + .pointer => unreachable, + else => break :b false, + } + }; + + if (direct) { + unreachable; + } else { + const stack = try builder.createStackVariable(unit, context, argument_type_index, indirect.alignment); + const indirect_value = V{ + .value = .{ + .runtime = stack, + }, + .type = indirect.pointer, + }; + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = indirect_value, + .source = argument_value, + }, + }); + try builder.appendInstruction(unit, context, store); + + argument_list.append_with_capacity(indirect_value); + } + }, + else => |t| @panic(@tagName(t)), } } @@ -10015,12 +11881,29 @@ pub const Builder = struct { try builder.buildTrap(unit, context); } - return .{ - .value = .{ - .runtime = instruction, - }, - .type = function_prototype.return_type, - }; + if (indirect_return) |v| { + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = v, + .type = function_prototype.return_type, + }, + }); + + try builder.appendInstruction(unit, context, load); + return .{ + .value = .{ + .runtime = load, + }, + .type = function_prototype.return_type, + }; + } else { + return .{ + .value = .{ + .runtime = instruction, + }, + .type = function_prototype.return_type, + }; + } } fn emitLocalVariableDeclaration(builder: *Builder, unit: *Unit, context: *const Context, token: Token.Index, mutability: Mutability, declaration_type: Type.Index, initialization: V, emit: bool, maybe_name: ?[]const u8) !Instruction.Index { @@ -10065,13 +11948,7 @@ pub const Builder = struct { try builder.current_scope.declarations.put_no_clobber(context.my_allocator, identifier_hash, &local_declaration.declaration); if (emit) { - const stack = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = declaration_type, - }, - }); - - try builder.appendInstruction(unit, context, stack); + const stack = try builder.createStackVariable(unit, context, declaration_type, null); assert(builder.current_scope.kind == .block); const local_scope = @fieldParentPtr(Debug.Scope.Local, "scope", builder.current_scope); @@ -10674,12 +12551,13 @@ pub const Builder = struct { else => |t| @panic(@tagName(t)), } - const catch_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = expression.type, - }, - }); - try builder.appendInstruction(unit, context, catch_alloca); + // const catch_alloca = try builder.c + // // const catch_alloca = try builder.createStackVariable(unit, context, catch_alloca); + // // .stack_slot = .{ + // // .type = expression.type, + // // },; + // // }); + // try builder.appendInstruction(unit, context, catch_alloca); const catch_type_expect = Type.Expect{ .type = error_union.type }; const is_error = try unit.instructions.append(context.my_allocator, .{ @@ -11005,7 +12883,54 @@ pub const Builder = struct { try unit.basic_blocks.get(new_basic_block).predecessors.append(context.my_allocator, builder.current_basic_block); } - fn resolveSwitch(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side) !V { + fn resolveComptimeSwitch(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, global_attributes: Debug.Declaration.Global.Attributes, node_index: Node.Index, maybe_global: ?*Debug.Declaration.Global) !V.Comptime { + const node = unit.getNode(node_index); + assert(node.id == .@"switch"); + const expression_to_switch_on = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null, .right); + const case_nodes = unit.getNodeList(node.right); + switch (expression_to_switch_on) { + .enum_value => |enum_field_index| { + const enum_field = unit.enum_fields.get(enum_field_index); + const enum_type = &unit.types.get(enum_field.parent).integer.kind.@"enum"; + const typecheck_enum_result = try unit.typecheckSwitchEnums(context, enum_type, case_nodes); + + const group_index = for (typecheck_enum_result.switch_case_groups.pointer[0..typecheck_enum_result.switch_case_groups.length], 0..) |switch_case_group, switch_case_group_index| { + break for (switch_case_group.pointer[0..switch_case_group.length]) |field_index| { + if (enum_field_index == field_index) { + break switch_case_group_index; + } + } else { + continue; + }; + } else typecheck_enum_result.else_switch_case_group_index orelse unreachable; + const true_switch_case_node = unit.getNode(case_nodes[group_index]); + return try builder.resolveComptimeValue(unit, context, type_expect, global_attributes, true_switch_case_node.right, maybe_global, .right); + }, + .bool => |boolean| { + assert(case_nodes.len == 2); + for (case_nodes) |case_node_index| { + const case_node = unit.getNode(case_node_index); + assert(case_node.left != .null); + assert(case_node.right != .null); + const boolean_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .bool }, .{}, case_node.left, null, .right); + switch (boolean_value) { + .bool => |case_boolean| { + if (case_boolean == boolean) { + return try builder.resolveComptimeValue(unit, context, type_expect, global_attributes, case_node.right, maybe_global, .right); + } + }, + else => |t| @panic(@tagName(t)), + } + } else { + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + } + } + + fn resolveSwitch(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side, maybe_global: ?*Debug.Declaration.Global) !V { + _ = maybe_global; const node = unit.getNode(node_index); assert(node.id == .@"switch"); const expression_to_switch_on = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.left, .right); @@ -11036,7 +12961,7 @@ pub const Builder = struct { const case_node = unit.getNode(case_node_index); assert(case_node.left != .null); assert(case_node.right != .null); - const boolean_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .bool }, .{}, case_node.left, null); + const boolean_value = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = .bool }, .{}, case_node.left, null, .right); switch (boolean_value) { .bool => |case_boolean| { if (case_boolean == boolean) { @@ -11095,12 +13020,12 @@ pub const Builder = struct { const condition_nodes = unit.getNodeListFromNode(condition_node); try conditions.ensure_capacity(context.my_allocator, @intCast(condition_nodes.len)); for (condition_nodes) |condition_node_index| { - const condition = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, condition_node_index, null); + const condition = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, condition_node_index, null, .right); conditions.append_with_capacity(condition); } }, else => { - const v = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, case_node.left, null); + const v = try builder.resolveComptimeValue(unit, context, Type.Expect{ .type = condition_type }, .{}, case_node.left, null, .right); try conditions.ensure_capacity(context.my_allocator, 1); conditions.append_with_capacity(v); }, @@ -11174,7 +13099,7 @@ pub const Builder = struct { const look_in_parent_scopes = false; const result: V = if (scope.lookupDeclaration(identifier_hash, look_in_parent_scopes)) |lookup| blk: { - const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration); + const global = try builder.referenceGlobalDeclaration(unit, context, lookup.scope, lookup.declaration, .{}); const pointer_type = try unit.getPointerType(context, .{ .type = global.declaration.type, .termination = .none, @@ -11806,12 +13731,7 @@ pub const Builder = struct { }); try builder.appendInstruction(unit, context, final_error_union); - const support_alloca = try unit.instructions.append(context.my_allocator, .{ - .stack_slot = .{ - .type = error_union.union_for_error, - }, - }); - try builder.appendInstruction(unit, context, support_alloca); + const support_alloca = try builder.createStackVariable(unit, context, error_union.union_for_error, null); const pointer_type = try unit.getPointerType(context, .{ .type = error_union.union_for_error, @@ -11864,7 +13784,7 @@ pub const Builder = struct { else => |t| @panic(@tagName(t)), } }, - .error_to_all_errors_error_union => return try builder.resolveErrorToAllErrorUnion(unit, context, ti, result), + .error_to_all_errors_error_union => return try builder.resolveErrorToAllErrorUnion(unit, context, ti, result), else => |t| @panic(@tagName(t)), } }, @@ -11941,22 +13861,10 @@ pub const Builder = struct { }); builder.return_block = try builder.newBasicBlock(unit, context); - const current_basic_block = builder.current_basic_block; - builder.current_basic_block = builder.return_block; - - try builder.appendInstruction(unit, context, builder.return_phi); const phi = &unit.instructions.get(builder.return_phi).phi; - try phi.addIncoming(context, return_value, current_basic_block); + try phi.addIncoming(context, return_value, builder.current_basic_block); - try builder.buildRet(unit, context, .{ - .value = .{ - .runtime = builder.return_phi, - }, - .type = return_type, - }); - - builder.current_basic_block = current_basic_block; try builder.jump(unit, context, builder.return_block); } else { try builder.buildRet(unit, context, return_value); @@ -11977,24 +13885,263 @@ pub const Builder = struct { } fn buildRet(builder: *Builder, unit: *Unit, context: *const Context, value: V) !void { + const function_definition = unit.function_definitions.get(builder.current_function); + const function_prototype_index = unit.types.get(function_definition.type).function; + const function_prototype = unit.function_prototypes.get(function_prototype_index); + // const LowerKind = union(enum){ + // direct, + // direct_pair: [2]Type.Index, + // }; + // _ = LowerKind; // autofix + const abi_value = switch (function_prototype.abi.return_type_abi.kind) { + .direct, .ignore => value, + .direct_pair => |pair| b: { + const struct_type_index = try unit.getTwoStruct(context, pair); + assert(struct_type_index == function_prototype.abi.return_type); + + if (struct_type_index == value.type) { + unreachable; + } else { + const stack = try builder.createStackVariable(unit, context, value.type, null); + const pointer_type = try unit.getPointerType(context, .{ + .type = value.type, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + const argument_alloca = V{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }; + + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = .{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }, + .source = value, + }, + }); + try builder.appendInstruction(unit, context, store); + + const target_type = unit.types.get(struct_type_index); + const target_size = target_type.getAbiSize(unit); + const target_alignment = target_type.getAbiAlignment(unit); + // const types = [2]*Type{unit.types.get(pair[0]), unit.types.get(pair[1])}; + const source_type = unit.types.get(value.type); + const source_size = source_type.getAbiSize(unit); + const source_alignment = target_type.getAbiAlignment(unit); + const target_is_scalable_vector_type = false; + const source_is_scalable_vector_type = false; + + if (source_size >= target_size and !source_is_scalable_vector_type and !target_is_scalable_vector_type) { + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = .{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }, + .type = struct_type_index, + }, + }); + try builder.appendInstruction(unit, context, load); + + break :b V{ + .value = .{ + .runtime = load, + }, + .type = struct_type_index, + }; + } else { + const alignment = @max(target_alignment, source_alignment); + const temporal = try builder.createStackVariable(unit, context, struct_type_index, alignment); + const coerced_pointer_type = try unit.getPointerType(context, .{ + .type = struct_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + const destination = V{ + .value = .{ + .runtime = temporal, + }, + .type = coerced_pointer_type, + }; + try builder.emitMemcpy(unit, context, .{ + .destination = destination, + .source = argument_alloca, + .destination_alignment = alignment, + .source_alignment = source_alignment, + .size = source_size, + .is_volatile = false, + }); + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = destination, + .type = struct_type_index, + .alignment = alignment, + }, + }); + try builder.appendInstruction(unit, context, load); + + break :b V{ + .value = .{ + .runtime = load, + }, + .type = struct_type_index, + }; + } + } + }, + .indirect => b: { + assert(function_definition.return_pointer != .null); + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = .{ + .value = .{ + .runtime = function_definition.return_pointer, + }, + .type = function_prototype.abi.parameter_types[0], + }, + .source = value, + }, + }); + try builder.appendInstruction(unit, context, store); + const void_value = V{ + .value = .{ + .@"comptime" = .void, + }, + .type = .void, + }; + break :b void_value; + }, + .direct_coerce => |coerced_type_index| if (coerced_type_index == value.type) value else b: { + const stack = try builder.createStackVariable(unit, context, value.type, null); + + const pointer_type = try unit.getPointerType(context, .{ + .type = value.type, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + const argument_alloca = V{ + .value = .{ + .runtime = stack, + }, + .type = pointer_type, + }; + + const store = try unit.instructions.append(context.my_allocator, .{ + .store = .{ + .destination = argument_alloca, + .source = value, + }, + }); + try builder.appendInstruction(unit, context, store); + + const target_type = unit.types.get(coerced_type_index); + const target_alignment = target_type.getAbiAlignment(unit); + const target_size = target_type.getAbiSize(unit); + // const types = [2]*Type{unit.types.get(pair[0]), unit.types.get(pair[1])}; + const source_type = unit.types.get(value.type); + const source_alignment = source_type.getAbiAlignment(unit); + const source_size = source_type.getAbiSize(unit); + const target_is_scalable_vector_type = false; + const source_is_scalable_vector_type = false; + + if (source_size >= target_size and !source_is_scalable_vector_type and !target_is_scalable_vector_type) { + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = argument_alloca, + .type = coerced_type_index, + }, + }); + try builder.appendInstruction(unit, context, load); + + break :b V{ + .value = .{ + .runtime = load, + }, + .type = coerced_type_index, + }; + } else { + const alignment = @max(target_alignment, source_alignment); + const temporal = try builder.createStackVariable(unit, context, coerced_type_index, alignment); + const coerced_pointer_type = try unit.getPointerType(context, .{ + .type = coerced_type_index, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + const destination = V{ + .value = .{ + .runtime = temporal, + }, + .type = coerced_pointer_type, + }; + try builder.emitMemcpy(unit, context, .{ + .destination = destination, + .source = argument_alloca, + .destination_alignment = alignment, + .source_alignment = source_alignment, + .size = source_size, + .is_volatile = false, + }); + const load = try unit.instructions.append(context.my_allocator, .{ + .load = .{ + .value = destination, + .type = coerced_type_index, + .alignment = alignment, + }, + }); + try builder.appendInstruction(unit, context, load); + + break :b V{ + .value = .{ + .runtime = load, + }, + .type = coerced_type_index, + }; + } + }, + else => |t| @panic(@tagName(t)), + }; const ret = try unit.instructions.append(context.my_allocator, .{ - .ret = value, + .ret = abi_value, }); try builder.appendInstruction(unit, context, ret); unit.basic_blocks.get(builder.current_basic_block).terminated = true; } fn reportCompileError(builder: *Builder, unit: *Unit, context: *const Context, err: Error) noreturn { - _ = context; // autofix const err_node = unit.getNode(err.node); const file = unit.files.get(builder.current_file); - _ = file; // autofix const token_debug_info = builder.getTokenDebugInfo(unit, err_node.token); - _ = token_debug_info; // autofix - // std.io.getStdOut().writer().print("{s}:{}:{}: \x1b[31merror:\x1b[0m ", .{ file.getPath(context.allocator) catch unreachable, token_debug_info.line + 1, token_debug_info.column + 1 }) catch unreachable; - // std.io.getStdOut().writer().writeAll(err.message) catch unreachable; - // std.io.getStdOut().writer().writeByte('\n') catch unreachable; - std.os.abort(); + const line = token_debug_info.line + 1; + const column = token_debug_info.column + 1; + const file_path = file.getPath(context.allocator) catch unreachable; + write(.panic, file_path) catch {}; + write(.panic, ":") catch {}; + Unit.dumpInt(line, 10, false) catch {}; + write(.panic, ":") catch {}; + Unit.dumpInt(column, 10, false) catch {}; + write(.panic, ":\x1b[0m ") catch {}; + write(.panic, err.message) catch {}; + write(.panic, "\n") catch {}; + std.posix.abort(); } fn reportFormattedCompileError(builder: *Builder, unit: *Unit, context: *const Context, node_index: Node.Index, comptime format: []const u8, args: anytype) noreturn { @@ -12158,6 +14305,7 @@ pub const Unit = struct { arrays: MyHashMap(Type.Array, Type.Index) = .{}, integers: MyHashMap(Type.Integer, Type.Index) = .{}, error_unions: MyHashMap(Type.Error.Union.Descriptor, Type.Index) = .{}, + two_structs: MyHashMap([2]Type.Index, Type.Index) = .{}, global_array_constants: MyHashMap(V.Comptime.ConstantArray.Index, *Debug.Declaration.Global) = .{}, error_count: u32 = 0, @@ -12181,6 +14329,8 @@ pub const Unit = struct { root_package: *Package = undefined, main_package: ?*Package = null, all_errors: Type.Index = .null, + cc_type: Type.Index = .null, + test_function_type: Type.Index = .null, descriptor: Descriptor, object_files: UnpinnedArray([*:0]const u8) = .{}, discard_identifiers: usize = 0, @@ -12305,9 +14455,9 @@ pub const Unit = struct { try write(.ir, ", "); try dumpInt(checkpoint.column, 10, false); }, - .argument_declaration => |arg| { + .debug_declare_argument => |debug_declare| { try write(.ir, "\""); - try write(.ir, unit.getIdentifier(arg.declaration.name)); + try write(.ir, unit.getIdentifier(debug_declare.argument.declaration.name)); try write(.ir, "\""); }, .cast => |cast| { @@ -12488,12 +14638,18 @@ pub const Unit = struct { unreachable; } - fn getExpectedTokenBytes(unit: *Unit, token_index: Token.Index, expected_id: Token.Id) []const u8 { + fn getTokenId(unit: *Unit, token_index: Token.Index) Token.Id { const index = Token.unwrap(token_index); assert(index < unit.token_buffer.length); const id = unit.token_buffer.ids[index]; + return id; + } + + fn getExpectedTokenBytes(unit: *Unit, token_index: Token.Index, expected_id: Token.Id) []const u8 { + const id = unit.getTokenId(token_index); // logln(.compilation, .token_bytes, "trying to get {s} from token of id {s}", .{ @tagName(expected_id), @tagName(id) }); if (id != expected_id) @panic("Unexpected token"); + const index = Token.unwrap(token_index); const offset = unit.token_buffer.offsets[index]; const len = unit.token_buffer.lengths[index]; const file_index = unit.findTokenFile(token_index); @@ -12562,6 +14718,7 @@ pub const Unit = struct { } pub fn getIntegerType(unit: *Unit, context: *const Context, integer: Type.Integer) !Type.Index { + // if (integer.bit_count > 64) unreachable; const existing_type_index: Type.Index = switch (integer.bit_count) { 8 => switch (integer.signedness) { .unsigned => .u8, @@ -12911,10 +15068,14 @@ pub const Unit = struct { const dot_index = data_structures.last(c_src, '.') orelse unreachable; const path_without_extension = c_src[0..dot_index]; const basename = std.fs.path.basename(path_without_extension); - const basename_z = try std.mem.joinZ(context.allocator, "/", &.{"nat", basename}); + const o_file = try std.mem.concat(context.allocator, u8, &.{ basename, ".o"}); + const basename_z = try std.mem.joinZ(context.allocator, "/", &.{ "nat", o_file, }); var c_flag = "-c".*; var o_flag = "-o".*; - var arguments = [_][*:0]u8{&c_flag, c_source_file, &o_flag, basename_z}; + var g_flag = "-g".*; + var stack_protector = "-fno-stack-protector".*; + + var arguments = [_][*:0]u8{ &c_flag, c_source_file, &o_flag, basename_z, &g_flag, &stack_protector }; try compileCSourceFile(context, &arguments); unit.object_files.append_with_capacity(basename_z); } @@ -12924,6 +15085,23 @@ pub const Unit = struct { try llvm.codegen(unit, context); } } + + fn getTwoStruct(unit: *Unit, context: *const Context, types: [2]Type.Index) !Type.Index { + if (unit.two_structs.get(types)) |result| return result else { + const two_struct = try unit.structs.append(context.my_allocator, .{ + .kind = .{ + .two_struct = types, + }, + }); + const type_index = try unit.types.append(context.my_allocator, .{ + .@"struct" = two_struct, + }); + + try unit.two_structs.put_no_clobber(context.my_allocator, types, type_index); + + return type_index; + } + } }; pub const FixedKeyword = enum { @@ -13283,7 +15461,7 @@ const LogKind = enum { const should_log_map = std.EnumSet(LogKind).initMany(&.{ // .parser, // .ir, - // .llvm, + //.llvm, .panic, }); diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index b7e9bf5..1380607 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -36,6 +36,7 @@ pub const LLVM = struct { llvm_instruction_map: MyHashMap(Compilation.Instruction.Index, *LLVM.Value) = .{}, llvm_value_map: MyHashMap(Compilation.V, *LLVM.Value) = .{}, llvm_block_map: MyHashMap(Compilation.BasicBlock.Index, *LLVM.Value.BasicBlock) = .{}, + llvm_external_functions: MyHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.Function) = .{}, global_variable_map: MyHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.GlobalVariable) = .{}, scope_map: MyHashMap(*Compilation.Debug.Scope, *LLVM.DebugInfo.Scope) = .{}, pointer_type: ?*LLVM.Type.Pointer = null, @@ -46,11 +47,20 @@ pub const LLVM = struct { return_phi_node: ?*LLVM.Value.Instruction.PhiNode = null, scope: *LLVM.DebugInfo.Scope = undefined, file: *LLVM.DebugInfo.File = undefined, + attributes: Attributes, // subprogram: *LLVM.DebugInfo.Subprogram = undefined, arg_index: u32 = 0, tag_count: c_uint = 0, inside_branch: bool = false, + pub const Attributes = struct { + noreturn: *Attribute, + naked: *Attribute, + nounwind: *Attribute, + inreg: *Attribute, + @"noalias": *Attribute, + }; + pub const Linkage = enum(c_uint) { @"extern" = 0, available_external = 1, @@ -80,6 +90,10 @@ pub const LLVM = struct { const getPointerType = bindings.NativityLLVMGetPointerType; const getStructType = bindings.NativityLLVMGetStructType; const getIntrinsicType = bindings.NativityLLVMContextGetIntrinsicType; + const getAttributeFromEnum = bindings.NativityLLVMContextGetAttributeFromEnum; + const getAttributeFromString = bindings.NativityLLVMContextGetAttributeFromString; + const getAttributeFromType = bindings.NativityLLVMContextGetAttributeFromType; + const getAttributeSet = bindings.NativityLLVMContextGetAttributeSet; }; pub const Module = opaque { @@ -130,6 +144,7 @@ pub const LLVM = struct { const createGlobalString = bindings.NativityLLVMBuilderCreateGlobalString; const createGlobalStringPointer = bindings.NativityLLVMBuilderCreateGlobalStringPointer; const createPhi = bindings.NativityLLVMBuilderCreatePhi; + const createMemcpy = bindings.NativityLLVMBuilderCreateMemcpy; const getInsertBlock = bindings.NativityLLVMBuilderGetInsertBlock; const isCurrentBlockTerminated = bindings.NativityLLVMBuilderIsCurrentBlockTerminated; @@ -552,90 +567,93 @@ pub const LLVM = struct { pub const Tuple = opaque {}; }; - pub const Attribute = enum(u32) { - AllocAlign = 1, - AllocatedPointer = 2, - AlwaysInline = 3, - Builtin = 4, - Cold = 5, - Convergent = 6, - DisableSanitizerInstrumentation = 7, - FnRetThunkExtern = 8, - Hot = 9, - ImmArg = 10, - InReg = 11, - InlineHint = 12, - JumpTable = 13, - MinSize = 14, - MustProgress = 15, - Naked = 16, - Nest = 17, - NoAlias = 18, - NoBuiltin = 19, - NoCallback = 20, - NoCapture = 21, - NoCfCheck = 22, - NoDuplicate = 23, - NoFree = 24, - NoImplicitFloat = 25, - NoInline = 26, - NoMerge = 27, - NoProfile = 28, - NoRecurse = 29, - NoRedZone = 30, - NoReturn = 31, - NoSanitizeBounds = 32, - NoSanitizeCoverage = 33, - NoSync = 34, - NoUndef = 35, - NoUnwind = 36, - NonLazyBind = 37, - NonNull = 38, - NullPointerIsValid = 39, - OptForFuzzing = 40, - OptimizeForSize = 41, - OptimizeNone = 42, - PresplitCoroutine = 43, - ReadNone = 44, - ReadOnly = 45, - Returned = 46, - ReturnsTwice = 47, - SExt = 48, - SafeStack = 49, - SanitizeAddress = 50, - SanitizeHWAddress = 51, - SanitizeMemTag = 52, - SanitizeMemory = 53, - SanitizeThread = 54, - ShadowCallStack = 55, - SkipProfile = 56, - Speculatable = 57, - SpeculativeLoadHardening = 58, - StackProtect = 59, - StackProtectReq = 60, - StackProtectStrong = 61, - StrictFP = 62, - SwiftAsync = 63, - SwiftError = 64, - SwiftSelf = 65, - WillReturn = 66, - WriteOnly = 67, - ZExt = 68, - ByRef = 69, - ByVal = 70, - ElementType = 71, - InAlloca = 72, - Preallocated = 73, - StructRet = 74, - Alignment = 75, - AllocKind = 76, - AllocSize = 77, - Dereferenceable = 78, - DereferenceableOrNull = 79, - Memory = 80, - StackAlignment = 81, - UWTable = 82, - VScaleRange = 83, + pub const Attribute = opaque { + pub const Set = opaque {}; + pub const Id = enum(u32) { + AllocAlign = 1, + AllocatedPointer = 2, + AlwaysInline = 3, + Builtin = 4, + Cold = 5, + Convergent = 6, + DisableSanitizerInstrumentation = 7, + FnRetThunkExtern = 8, + Hot = 9, + ImmArg = 10, + InReg = 11, + InlineHint = 12, + JumpTable = 13, + MinSize = 14, + MustProgress = 15, + Naked = 16, + Nest = 17, + NoAlias = 18, + NoBuiltin = 19, + NoCallback = 20, + NoCapture = 21, + NoCfCheck = 22, + NoDuplicate = 23, + NoFree = 24, + NoImplicitFloat = 25, + NoInline = 26, + NoMerge = 27, + NoProfile = 28, + NoRecurse = 29, + NoRedZone = 30, + NoReturn = 31, + NoSanitizeBounds = 32, + NoSanitizeCoverage = 33, + NoSync = 34, + NoUndef = 35, + NoUnwind = 36, + NonLazyBind = 37, + NonNull = 38, + NullPointerIsValid = 39, + OptForFuzzing = 40, + OptimizeForSize = 41, + OptimizeNone = 42, + PresplitCoroutine = 43, + ReadNone = 44, + ReadOnly = 45, + Returned = 46, + ReturnsTwice = 47, + SExt = 48, + SafeStack = 49, + SanitizeAddress = 50, + SanitizeHWAddress = 51, + SanitizeMemTag = 52, + SanitizeMemory = 53, + SanitizeThread = 54, + ShadowCallStack = 55, + SkipProfile = 56, + Speculatable = 57, + SpeculativeLoadHardening = 58, + StackProtect = 59, + StackProtectReq = 60, + StackProtectStrong = 61, + StrictFP = 62, + SwiftAsync = 63, + SwiftError = 64, + SwiftSelf = 65, + WillReturn = 66, + WriteOnly = 67, + ZExt = 68, + ByRef = 69, + ByVal = 70, + ElementType = 71, + InAlloca = 72, + Preallocated = 73, + StructRet = 74, + Alignment = 75, + AllocKind = 76, + AllocSize = 77, + Dereferenceable = 78, + DereferenceableOrNull = 79, + Memory = 80, + StackAlignment = 81, + UWTable = 82, + VScaleRange = 83, + }; }; pub const Type = opaque { @@ -647,6 +665,7 @@ pub const LLVM = struct { const isPointer = bindings.NativityLLVMTypeIsPointer; const isInteger = bindings.NativityLLVMTypeIsInteger; const isVoid = bindings.NativityLLVMTypeIsVoid; + const assertEqual = bindings.NativityLLVMTypeAssertEqual; pub const Array = opaque { fn toType(integer: *@This()) *Type { @@ -748,6 +767,7 @@ pub const LLVM = struct { pub const Call = opaque { const setCallingConvention = bindings.NativityLLVMCallSetCallingConvention; + const setAttributes = bindings.NativityLLVMCallSetAttributes; fn toValue(this: *@This()) *Value { return @ptrCast(this); } @@ -860,15 +880,17 @@ pub const LLVM = struct { pub const Constant = opaque { pub const Function = opaque { + const getArgument = bindings.NativityLLVMFunctionGetArgument; const getArguments = bindings.NativityLLVMFunctionGetArguments; const getType = bindings.NativityLLVMFunctionGetType; - const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey; + // const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey; const verify = bindings.NativityLLVMVerifyFunction; const toString = bindings.NativityLLVMFunctionToString; const setCallingConvention = bindings.NativityLLVMFunctionSetCallingConvention; const getCallingConvention = bindings.NativityLLVMFunctionGetCallingConvention; const setSubprogram = bindings.NativityLLVMFunctionSetSubprogram; const getSubprogram = bindings.NativityLLVMFunctionGetSubprogram; + const setAttributes = bindings.NativityLLVMFunctionSetAttributes; fn toValue(this: *@This()) *Value { return @ptrCast(this); @@ -1181,21 +1203,11 @@ pub const LLVM = struct { const llvm_type: *LLVM.Type = switch (sema_type.*) { .function => |function_prototype_index| blk: { const sema_function_prototype = unit.function_prototypes.get(function_prototype_index); - const llvm_return_type = try llvm.getType(unit, context, sema_function_prototype.return_type); - var parameter_types = try UnpinnedArray(*LLVM.Type).initialize_with_capacity(context.my_allocator, @intCast(sema_function_prototype.argument_types.len)); + const llvm_return_type = try llvm.getType(unit, context, sema_function_prototype.abi.return_type); + var parameter_types = try UnpinnedArray(*LLVM.Type).initialize_with_capacity(context.my_allocator, @intCast(sema_function_prototype.abi.parameter_types.len)); - for (sema_function_prototype.argument_types) |argument_type_index| { - switch (unit.types.get(argument_type_index).*) { - // TODO: ABI - .integer, - .pointer, - // .@"enum", - .@"struct", - .slice, - // .bool, - => parameter_types.append_with_capacity(try llvm.getType(unit, context, argument_type_index)), - else => |t| @panic(@tagName(t)), - } + for (sema_function_prototype.abi.parameter_types) |argument_type_index| { + parameter_types.append_with_capacity(try llvm.getType(unit, context, argument_type_index)); } const is_var_args = false; @@ -1265,6 +1277,16 @@ pub const LLVM = struct { break :blk struct_type.toType(); }, + .two_struct => |pair| blk: { + const types = [2]*LLVM.Type{ + try llvm.getType(unit, context, pair[0]), + try llvm.getType(unit, context, pair[1]), + }; + const is_packed = false; + const struct_type = llvm.context.getStructType(&types, types.len, is_packed) orelse return Type.Error.@"struct"; + + break :blk struct_type.toType(); + }, else => |t| @panic(@tagName(t)), }, .array => |array| blk: { @@ -1289,11 +1311,12 @@ pub const LLVM = struct { if (llvm.debug_info_file_map.get(sema_file_index)) |file| { return file; } else { + // if (@intFromEnum(sema_file_index) == 4) @breakpoint(); const sema_file = unit.files.get(sema_file_index); - const sub_path = std.fs.path.dirname(sema_file.relative_path) orelse ""; - const file_path = std.fs.path.basename(sema_file.relative_path); - const directory_path = try Compilation.joinPath(context, sema_file.package.directory.path, sub_path); - const debug_file = llvm.debug_info_builder.createFile(file_path.ptr, file_path.len, directory_path.ptr, directory_path.len) orelse unreachable; + const full_path = try Compilation.joinPath(context, sema_file.package.directory.path, sema_file.relative_path); + const filename = std.fs.path.basename(full_path); + const directory = full_path[0 .. full_path.len - filename.len]; + const debug_file = llvm.debug_info_builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len) orelse unreachable; try llvm.debug_info_file_map.put_no_clobber(context.my_allocator, sema_file_index, debug_file); return debug_file; } @@ -1868,6 +1891,7 @@ pub const LLVM = struct { .global => |global| { const constant = switch (global.initial_value) { .function_definition => llvm.function_definition_map.get(global).?.toConstant(), + .function_declaration => llvm.llvm_external_functions.get(global).?.toConstant(), else => llvm.global_variable_map.get(global).?.toConstant(), }; return constant; @@ -1968,7 +1992,7 @@ pub const LLVM = struct { const len = llvm.context.getConstantInt(64, 0, false) orelse unreachable; break :b .{ ptr.toConstant(), len.toConstant() }; }; - + const constant_slice = slice_struct_type.getConstant(&slice_fields, slice_fields.len) orelse unreachable; return constant_slice; } @@ -2040,7 +2064,97 @@ pub const LLVM = struct { return call.toValue(); } + fn emitParameterAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, abi: Compilation.Function.AbiInfo, is_return: bool) !*const LLVM.Attribute.Set { + var attributes = UnpinnedArray(*LLVM.Attribute){}; + if (abi.attributes.by_reg) { + try attributes.append(context.my_allocator, llvm.attributes.inreg); + } + switch (abi.kind) { + .ignore => { + assert(is_return); + }, + .direct, .direct_pair, .direct_coerce => {}, + .indirect => |indirect| { + const indirect_type = try llvm.getType(unit, context, indirect.type); + if (is_return) { + const sret = llvm.context.getAttributeFromType(.StructRet, indirect_type); + try attributes.append(context.my_allocator, sret); + try attributes.append(context.my_allocator, llvm.attributes.@"noalias"); + // TODO: alignment + } else { + if (abi.attributes.by_value) { + const byval = llvm.context.getAttributeFromType(.ByVal, indirect_type); + try attributes.append(context.my_allocator, byval); + } + //TODO: alignment + } + }, + else => |t| @panic(@tagName(t)), + } + const attribute_set = llvm.context.getAttributeSet(attributes.pointer, attributes.length); + return attribute_set; + } + + fn getFunctionAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, function_prototype: *Compilation.Function.Prototype) !*const LLVM.Attribute.Set { + var function_attributes = UnpinnedArray(*LLVM.Attribute){}; + try function_attributes.append(context.my_allocator, llvm.attributes.nounwind); + + switch (unit.types.get(function_prototype.return_type).*) { + .noreturn => { + try function_attributes.append(context.my_allocator, llvm.attributes.noreturn); + }, + else => {}, + } + + if (function_prototype.attributes.naked) { + try function_attributes.append(context.my_allocator, llvm.attributes.naked); + } + + const function_attribute_set = llvm.context.getAttributeSet(function_attributes.pointer, function_attributes.length); + return function_attribute_set; + } + + const CallOrFunction = union(enum) { + call: *LLVM.Value.Instruction.Call, + function: *LLVM.Value.Constant.Function, + }; + + fn setCallOrFunctionAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, function_prototype: *Compilation.Function.Prototype, call_or_function: CallOrFunction) !void { + const function_attribute_set = try llvm.getFunctionAttributes(unit, context, function_prototype); + + var parameter_attribute_sets = try UnpinnedArray(*const LLVM.Attribute.Set).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.abi.parameter_types_abi.len + @intFromBool(function_prototype.abi.return_type_abi.kind == .indirect))); + const return_attribute_set = blk: { + const attribute_set = try llvm.emitParameterAttributes(unit, context, function_prototype.abi.return_type_abi, true); + break :blk switch (function_prototype.abi.return_type_abi.kind) { + .indirect => b: { + parameter_attribute_sets.append_with_capacity(attribute_set); + break :b llvm.context.getAttributeSet(null, 0); + }, + else => attribute_set, + }; + }; + + for (function_prototype.abi.parameter_types_abi) |parameter_type_abi| { + const parameter_attribute_set = try llvm.emitParameterAttributes(unit, context, parameter_type_abi, false); + parameter_attribute_sets.append_with_capacity(parameter_attribute_set); + } + + const calling_convention = getCallingConvention(function_prototype.calling_convention); + + switch (call_or_function) { + .call => |call| { + call.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length); + call.setCallingConvention(calling_convention); + }, + .function => |function| { + function.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length); + function.setCallingConvention(calling_convention); + }, + } + } + fn emitFunctionDeclaration(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, declaration: *Compilation.Debug.Declaration.Global) !void { + const name = unit.getIdentifier(declaration.declaration.name); const function_type = try llvm.getType(unit, context, declaration.declaration.type); const is_export = declaration.attributes.contains(.@"export"); const is_extern = declaration.attributes.contains(.@"extern"); @@ -2053,23 +2167,35 @@ pub const LLVM = struct { // TODO: Check name collision const mangle_name = !export_or_extern; _ = mangle_name; // autofix - const name = unit.getIdentifier(declaration.declaration.name); const function = llvm.module.createFunction(function_type.toFunction() orelse unreachable, linkage, address_space, name.ptr, name.len) orelse return Error.function; const function_prototype = unit.function_prototypes.get(unit.types.get(declaration.declaration.type).function); - switch (unit.types.get(function_prototype.return_type).*) { - .noreturn => { - function.addAttributeKey(.NoReturn); - }, - else => {}, - } + try llvm.setCallOrFunctionAttributes(unit, context, function_prototype, .{ + .function = function, + }); + // const calling_convention = getCallingConvention(function_prototype.calling_convention); + // function.setCallingConvention(calling_convention); + // + // const function_attribute_set = llvm.getFunctionAttributes(unit, context, function_prototype); + // + // var parameter_attribute_sets = try UnpinnedArray(*const LLVM.Attribute.Set).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.abi.parameter_types_abi.len + @intFromBool(function_prototype.abi.return_type_abi.kind == .indirect))); + // const return_attribute_set = blk: { + // const attribute_set = try llvm.emitParameterAttributes(unit, context, function_prototype.abi.return_type_abi, true); + // break :blk switch (function_prototype.abi.return_type_abi.kind) { + // .indirect => b: { + // parameter_attribute_sets.append_with_capacity(attribute_set); + // break :b llvm.context.getAttributeSet(null, 0); + // }, + // else => attribute_set, + // }; + // }; + // + // for (function_prototype.abi.parameter_types_abi) |parameter_type_abi| { + // const parameter_attribute_set = try llvm.emitParameterAttributes(unit, context, parameter_type_abi, false); + // parameter_attribute_sets.append_with_capacity(parameter_attribute_set); + // } - if (function_prototype.attributes.naked) { - function.addAttributeKey(.Naked); - } - - const calling_convention = getCallingConvention(function_prototype.calling_convention); - function.setCallingConvention(calling_convention); + // function.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length); switch (declaration.initial_value) { .function_declaration => try llvm.function_declaration_map.put_no_clobber(context.my_allocator, declaration, function), @@ -2078,6 +2204,7 @@ pub const LLVM = struct { } if (unit.descriptor.generate_debug_information) { + // if (data_structures.byte_equal(name, "nat_split_struct_ints")) @breakpoint(); const debug_file = try llvm.getDebugInfoFile(unit, context, declaration.declaration.scope.file); var parameter_types = try UnpinnedArray(*LLVM.DebugInfo.Type).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.argument_types.len)); for (function_prototype.argument_types) |argument_type_index| { @@ -2116,7 +2243,6 @@ pub const LLVM = struct { }; const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none; const subroutine_type = llvm.debug_info_builder.createSubroutineType(parameter_types.pointer, parameter_types.length, subroutine_type_flags, subroutine_type_calling_convention) orelse unreachable; - const scope_line = 0; const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{ .virtuality = .none, .local_to_unit = !export_or_extern, @@ -2131,11 +2257,13 @@ pub const LLVM = struct { }; const subprogram_declaration = null; const function_name = unit.getIdentifier(declaration.declaration.name); - const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, declaration.declaration.line + 1, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable; + const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, declaration.declaration.line + 1, subroutine_type, declaration.declaration.line + 1, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable; function.setSubprogram(subprogram); switch (declaration.initial_value) { - .function_declaration => {}, + .function_declaration => { + try llvm.llvm_external_functions.put_no_clobber(context.my_allocator, declaration, function); + }, .function_definition => |function_definition_index| { const function_definition = unit.function_definitions.get(function_definition_index); const scope = subprogram.toLocalScope().toScope(); @@ -2185,12 +2313,20 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo .module = module, .builder = builder, .debug_info_builder = module.createDebugInfoBuilder() orelse return Error.debug_info_builder, + .attributes = .{ + .naked = llvm_context.getAttributeFromEnum(.Naked, 0), + .noreturn = llvm_context.getAttributeFromEnum(.NoReturn, 0), + .nounwind = llvm_context.getAttributeFromEnum(.NoUnwind, 0), + .inreg = llvm_context.getAttributeFromEnum(.InReg, 0), + .@"noalias" = llvm_context.getAttributeFromEnum(.NoAlias, 0), + }, }; if (unit.descriptor.generate_debug_information) { - const filename = "main"; - const directory = "."; - const debug_info_file = llvm.debug_info_builder.createFile(filename, filename.len, directory, directory.len) orelse unreachable; + const full_path = try std.fs.cwd().realpathAlloc(context.allocator, unit.descriptor.main_package_path); + const filename = std.fs.path.basename(full_path); + const directory = full_path[0 .. full_path.len - filename.len]; + const debug_info_file = llvm.debug_info_builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len) orelse unreachable; const producer = "nativity"; const is_optimized = false; const flags = ""; @@ -2291,7 +2427,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo llvm.scope = subprogram.toLocalScope().toScope(); } - llvm.arg_index = 0; var alloca_map = MyHashMap(Compilation.Instruction.Index, *LLVM.Value){}; var block_command_list = BasicBlockList{}; @@ -2438,18 +2573,23 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call.toValue()); }, .stack_slot => |stack_slot| { + // const stack_slot_type = unit.types.get(stack_slot.type); + // const stack_slot_alignment = stack_slot_type.getAbiAlignment(unit); const declaration_type = try llvm.getType(unit, context, stack_slot.type); + const type_alignment = unit.types.get(stack_slot.type).getAbiAlignment(unit); const alloca_array_size = null; - const declaration_alloca = llvm.builder.createAlloca(declaration_type, address_space, alloca_array_size, "", "".len) orelse return LLVM.Value.Instruction.Error.alloca; + const declaration_alloca = llvm.builder.createAlloca(declaration_type, address_space, alloca_array_size, "", "".len, type_alignment) orelse return LLVM.Value.Instruction.Error.alloca; try alloca_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue()); try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue()); }, .store => |store| { const right = try llvm.emitRightValue(unit, context, store.source); + const source_type = unit.types.get(store.source.type); + const alignment = source_type.getAbiAlignment(unit); const is_volatile = false; const left = try llvm.emitLeftValue(unit, context, store.destination); - const store_instruction = llvm.builder.createStore(right, left, is_volatile) orelse return LLVM.Value.Instruction.Error.store; + const store_instruction = llvm.builder.createStore(right, left, is_volatile, alignment) orelse return LLVM.Value.Instruction.Error.store; _ = store_instruction; // autofix }, .cast => |cast| { @@ -2469,6 +2609,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo .slice_to_nullable, .slice_to_not_null, .slice_coerce_to_zero_termination, + .slice_zero_to_no_termination, .pointer_to_nullable, .pointer_const_to_var, .pointer_to_array_to_pointer_to_many, @@ -2515,9 +2656,11 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo break :blk value; }; + const load_type = unit.types.get(load.type); + const alignment = if (load.alignment) |alignment| alignment else load_type.getAbiAlignment(unit); const value_type = try llvm.getType(unit, context, load.type); const is_volatile = false; - const load_i = llvm.builder.createLoad(value_type, value, is_volatile, "", "".len) orelse return LLVM.Value.Instruction.Error.load; + const load_i = llvm.builder.createLoad(value_type, value, is_volatile, "", "".len, alignment) orelse return LLVM.Value.Instruction.Error.load; try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, load_i.toValue()); }, .integer_binary_operation => |binary_operation| { @@ -2553,66 +2696,60 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo }; try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, instruction); }, - .call => |call| { + .call => |sema_call| { var argument_buffer: [32]*LLVM.Value = undefined; - const argument_count = call.arguments.len; + const argument_count = sema_call.arguments.len; const arguments = argument_buffer[0..argument_count]; - switch (call.callable.value) { - .@"comptime" => |ct| switch (ct) { - .global => |call_function_declaration| { - const call_function_type = call_function_declaration.declaration.type; - const call_function_prototype = unit.function_prototypes.get(unit.types.get(call_function_type).function); - assert(call_function_type == call.function_type); + const call_function_type = unit.types.get(sema_call.function_type); + const function_prototype = unit.function_prototypes.get(call_function_type.function); + const call_type = try llvm.getType(unit, context, sema_call.function_type); + const call = switch (sema_call.callable.value) { + .@"comptime" => |ct| switch (ct) { + .global => |call_function_declaration| b: { const callee = switch (call_function_declaration.initial_value) { .function_definition => llvm.function_definition_map.get(call_function_declaration).?, .function_declaration => llvm.function_declaration_map.get(call_function_declaration).?, else => |t| @panic(@tagName(t)), }; - for (call.arguments, arguments) |argument_value, *argument| { + for (sema_call.arguments, arguments) |argument_value, *argument| { argument.* = try llvm.emitRightValue(unit, context, argument_value); } - - const llvm_calling_convention = callee.getCallingConvention(); const name = ""; - const call_type = try llvm.getType(unit, context, call.function_type); + const function_name = unit.getIdentifier(call_function_declaration.declaration.name); + _ = function_name; // autofix const function_type = call_type.toFunction() orelse unreachable; - for (call.arguments, arguments, call_function_prototype.argument_types, 0..) |sema_argument, argument, sema_argument_type, i| { + for (sema_call.arguments, arguments, function_prototype.abi.parameter_types, 0..) |sema_argument, argument, sema_argument_type, i| { assert(sema_argument.type == sema_argument_type); const argument_type = function_type.getArgumentType(@intCast(i)); - assert(argument_type == argument.getType()); + argument_type.assertEqual(argument.getType()); } const call_instruction = llvm.builder.createCall(function_type, callee.toValue(), arguments.ptr, arguments.len, name.ptr, name.len, null) orelse return LLVM.Value.Instruction.Error.call; - call_instruction.setCallingConvention(llvm_calling_convention); - - try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call_instruction.toValue()); + break :b call_instruction; }, else => |t| @panic(@tagName(t)), }, - .runtime => |ii| { + .runtime => |ii| b: { const callee = llvm.llvm_instruction_map.get(ii).?; - const callable_type = unit.types.get(call.function_type); - const sema_calling_convention = switch (callable_type.*) { - .function => |function_prototype_index| unit.function_prototypes.get(function_prototype_index).calling_convention, - else => |t| @panic(@tagName(t)), - }; - const calling_convention = getCallingConvention(sema_calling_convention); - for (call.arguments, arguments) |argument_value, *argument| { + for (sema_call.arguments, arguments) |argument_value, *argument| { argument.* = try llvm.emitRightValue(unit, context, argument_value); } const name = ""; - const call_type = try llvm.getType(unit, context, call.function_type); const function_type = call_type.toFunction() orelse unreachable; const call_instruction = llvm.builder.createCall(function_type, callee, arguments.ptr, arguments.len, name.ptr, name.len, null) orelse return LLVM.Value.Instruction.Error.call; - call_instruction.setCallingConvention(calling_convention); - - try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call_instruction.toValue()); + break :b call_instruction; }, else => |t| @panic(@tagName(t)), - } + }; + + try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call.toValue()); + + try llvm.setCallOrFunctionAttributes(unit, context, function_prototype, .{ + .call = call, + }); }, .ret => |return_value| { const value = switch (return_value.type) { @@ -2670,25 +2807,16 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo .@"unreachable" => { _ = llvm.builder.createUnreachable() orelse return LLVM.Value.Instruction.Error.@"unreachable"; }, - .argument_declaration => |argument_declaration| { - var argument_buffer: [16]*LLVM.Value.Argument = undefined; - var argument_count: usize = argument_buffer.len; - llvm.function.getArguments(&argument_buffer, &argument_count); - const arguments = argument_buffer[0..argument_count]; - const argument_index = llvm.arg_index; - llvm.arg_index += 1; - const argument = arguments[argument_index]; - const name = unit.getIdentifier(argument_declaration.declaration.name); - argument.toValue().setName(name.ptr, name.len); - const argument_type_index = argument_declaration.declaration.type; - _ = argument_type_index; // autofix - const argument_type = argument.toValue().getType(); - const alloca_array_size: ?*LLVM.Value = null; - const argument_value = argument.toValue(); - const declaration_alloca = llvm.builder.createAlloca(argument_type, address_space, alloca_array_size, "", "".len) orelse return LLVM.Value.Instruction.Error.alloca; - + .abi_argument => |argument_index| { + const argument = llvm.function.getArgument(argument_index) orelse unreachable; + try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, argument.toValue()); + }, + .debug_declare_argument => |debug_declare| { if (unit.descriptor.generate_debug_information) { - const debug_declaration_type = try llvm.getDebugType(unit, context, argument_declaration.declaration.type); + const argument_index: c_uint = debug_declare.argument.index; + const declaration = &debug_declare.argument.declaration; + const debug_declaration_type = try llvm.getDebugType(unit, context, declaration.type); + const declaration_alloca = llvm.llvm_instruction_map.get(debug_declare.stack).?; const always_preserve = true; const flags = LLVM.DebugInfo.Node.Flags{ .visibility = .none, @@ -2719,65 +2847,61 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo .little_endian = false, .all_calls_described = false, }; - const declaration_name = unit.getIdentifier(argument_declaration.declaration.name); - const line = argument_declaration.declaration.line; - const column = argument_declaration.declaration.column; + const declaration_name = unit.getIdentifier(declaration.name); + const line = declaration.line; + const column = declaration.column; const debug_parameter_variable = llvm.debug_info_builder.createParameterVariable(llvm.scope, declaration_name.ptr, declaration_name.len, argument_index + 1, llvm.file, line, debug_declaration_type, always_preserve, flags) orelse unreachable; - const insert_declare = llvm.debug_info_builder.insertDeclare(declaration_alloca.toValue(), debug_parameter_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable); + const insert_declare = llvm.debug_info_builder.insertDeclare(declaration_alloca, debug_parameter_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable); _ = insert_declare; } - - const is_volatile = false; - const store = llvm.builder.createStore(argument_value, declaration_alloca.toValue(), is_volatile) orelse return LLVM.Value.Instruction.Error.store; - _ = store; // autofix - try llvm.argument_allocas.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue()); - try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue()); }, .debug_declare_local_variable => |declare_local_variable| { - const local_variable = declare_local_variable.variable; - const debug_declaration_type = try llvm.getDebugType(unit, context, local_variable.declaration.type); - const always_preserve = true; - const flags = LLVM.DebugInfo.Node.Flags{ - .visibility = .none, - .forward_declaration = false, - .apple_block = false, - .block_by_ref_struct = false, - .virtual = false, - .artificial = false, - .explicit = false, - .prototyped = false, - .objective_c_class_complete = false, - .object_pointer = false, - .vector = false, - .static_member = false, - .lvalue_reference = false, - .rvalue_reference = false, - .reserved = false, - .inheritance = .none, - .introduced_virtual = false, - .bit_field = false, - .no_return = false, - .type_pass_by_value = false, - .type_pass_by_reference = false, - .enum_class = false, - .thunk = false, - .non_trivial = false, - .big_endian = false, - .little_endian = false, - .all_calls_described = false, - }; + if (unit.descriptor.generate_debug_information) { + const local_variable = declare_local_variable.variable; + const debug_declaration_type = try llvm.getDebugType(unit, context, local_variable.declaration.type); + const always_preserve = true; + const flags = LLVM.DebugInfo.Node.Flags{ + .visibility = .none, + .forward_declaration = false, + .apple_block = false, + .block_by_ref_struct = false, + .virtual = false, + .artificial = false, + .explicit = false, + .prototyped = false, + .objective_c_class_complete = false, + .object_pointer = false, + .vector = false, + .static_member = false, + .lvalue_reference = false, + .rvalue_reference = false, + .reserved = false, + .inheritance = .none, + .introduced_virtual = false, + .bit_field = false, + .no_return = false, + .type_pass_by_value = false, + .type_pass_by_reference = false, + .enum_class = false, + .thunk = false, + .non_trivial = false, + .big_endian = false, + .little_endian = false, + .all_calls_described = false, + }; - const alignment = 0; - const declaration_name = unit.getIdentifier(local_variable.declaration.name); - const line = local_variable.declaration.line; - const column = local_variable.declaration.column; - const debug_local_variable = llvm.debug_info_builder.createAutoVariable(llvm.scope, declaration_name.ptr, declaration_name.len, llvm.file, line, debug_declaration_type, always_preserve, flags, alignment) orelse unreachable; + const alignment = 0; + const declaration_name = unit.getIdentifier(local_variable.declaration.name); + const line = local_variable.declaration.line; + const column = local_variable.declaration.column; + const debug_local_variable = llvm.debug_info_builder.createAutoVariable(llvm.scope, declaration_name.ptr, declaration_name.len, llvm.file, line, debug_declaration_type, always_preserve, flags, alignment) orelse unreachable; - const local = alloca_map.get(declare_local_variable.stack).?; + const local = alloca_map.get(declare_local_variable.stack).?; - const insert_declare = llvm.debug_info_builder.insertDeclare(local, debug_local_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable); - _ = insert_declare; + const insert_declare = llvm.debug_info_builder.insertDeclare(local, debug_local_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable); + _ = insert_declare; + } }, .insert_value => |insert_value| { const aggregate = try llvm.emitRightValue(unit, context, insert_value.expression); @@ -2916,6 +3040,21 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const switch_instruction = llvm.builder.createSwitch(condition, else_block, condition_array.pointer, basic_block_array.pointer, condition_array.length, branch_weights, unpredictable); try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, switch_instruction.toValue()); }, + .memcpy => |memcpy| { + const destination = try llvm.emitLeftValue(unit, context, memcpy.destination); + const source = try llvm.emitLeftValue(unit, context, memcpy.source); + const destination_alignment = if (memcpy.destination_alignment) |alignment| alignment else b: { + const ty = unit.types.get(memcpy.destination.type); + const alignment = ty.getAbiAlignment(unit); + break :b alignment; + }; + const source_alignment = if (memcpy.source_alignment) |alignment| alignment else b: { + const ty = unit.types.get(memcpy.source.type); + const alignment = ty.getAbiAlignment(unit); + break :b alignment; + }; + _ = llvm.builder.createMemcpy(destination, destination_alignment, source, source_alignment, memcpy.size, memcpy.is_volatile); + }, else => |t| @panic(@tagName(t)), } } @@ -2965,7 +3104,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const module_dump = module_ptr[0..module_len]; _ = module_dump; // autofix - try write(.llvm, function_ir); + try write(.panic, function_ir); const error_message = message_ptr[0..message_len]; try write(.panic, error_message); // std.debug.print("\nLLVM verification for function inside module failed:\nFull module: {s}\n```\n{s}\n```\n{s}\n", .{ module_dump, function_ir, error_message }); @@ -2982,6 +3121,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo // logln(.llvm, .print_module, "{s}", .{module_string}); const verify_module = true; + const print_module = true; if (verify_module) { var message_ptr: [*]const u8 = undefined; var message_len: usize = 0; @@ -2995,6 +3135,12 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo } } + if (print_module) { + try write(.llvm, "Module: \n"); + try write(.llvm, module_string); + try write(.llvm, "\n"); + } + // TODO: initialize only the target we are going to use bindings.NativityLLVMInitializeCodeGeneration(); // TODO: proper target selection diff --git a/bootstrap/backend/llvm_bindings.zig b/bootstrap/backend/llvm_bindings.zig index 9c0e11e..17b590a 100644 --- a/bootstrap/backend/llvm_bindings.zig +++ b/bootstrap/backend/llvm_bindings.zig @@ -50,21 +50,29 @@ pub extern fn NativityLLVMValueSetName(value: *LLVM.Value, name_ptr: [*]const u8 pub extern fn NativityLLVMValueGetType(value: *LLVM.Value) *LLVM.Type; pub extern fn NativityLLVMArgumentGetIndex(argument: *LLVM.Value.Argument) c_uint; pub extern fn NativityLLVMFunctionGetArguments(function: *LLVM.Value.Constant.Function, argument_ptr: [*]*LLVM.Value.Argument, argument_len: *usize) void; +pub extern fn NativityLLVMFunctionGetArgument(function: *LLVM.Value.Constant.Function, index: c_uint) ?*LLVM.Value.Argument; pub extern fn NativityLLVMFunctionGetType(function: *LLVM.Value.Constant.Function) *LLVM.Type.Function; pub extern fn NativityLLVMFunctionTypeGetReturnType(function_type: *LLVM.Type.Function) *LLVM.Type; pub extern fn NativityLLVMTypeIsVoid(type: *LLVM.Type) bool; -pub extern fn NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Instruction.Alloca; -pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool) ?*LLVM.Value.Instruction.Store; +pub extern fn NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*LLVM.Value.Instruction.Alloca; +pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool, alignment: u32) ?*LLVM.Value.Instruction.Store; +pub extern fn NativityLLVMBuilderCreateMemcpy(builder: *LLVM.Builder, destination: *LLVM.Value, destination_alignment: u32, source: *LLVM.Value, source_alignment: u32, size: u64, is_volatile: bool) *LLVM.Value.Instruction.Call; pub extern fn NativityLLVMContextGetConstantInt(context: *LLVM.Context, bit_count: c_uint, value: u64, is_signed: bool) ?*LLVM.Value.Constant.Int; pub extern fn NativityLLVMContextGetConstantString(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, null_terminate: bool) ?*LLVM.Value.Constant; pub extern fn NativityLLVMGetConstantArray(array_type: *LLVM.Type.Array, value_ptr: [*]const *LLVM.Value.Constant, value_count: usize) ?*LLVM.Value.Constant; pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) ?*LLVM.Value.Constant; pub extern fn NativityLLVMConstantToInt(constant: *LLVM.Value.Constant) ?*LLVM.Value.Constant.Int; pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Instruction.Load; +pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*LLVM.Value.Instruction.Load; pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) ?*LLVM.Value.Instruction.Ret; pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value; -pub extern fn NativityLLVMFunctionAddAttributeKey(builder: *LLVM.Value.Constant.Function, attribute_key: LLVM.Attribute) void; +pub extern fn NativityLLVMContextGetAttributeFromEnum(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, attribute_value: u64) *LLVM.Attribute; +pub extern fn NativityLLVMContextGetAttributeFromString(context: *LLVM.Context, key_ptr: [*]const u8, key_len: usize, value_ptr: [*]const u8, value_len: usize) *LLVM.Attribute; +pub extern fn NativityLLVMContextGetAttributeFromType(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, type: *LLVM.Type) *LLVM.Attribute; +pub extern fn NativityLLVMContextGetAttributeSet(context: *LLVM.Context, attribute_ptr: ?[*]const *LLVM.Attribute, attribute_count: usize) *const LLVM.Attribute.Set; +pub extern fn NativityLLVMFunctionSetAttributes(function: *LLVM.Value.Constant.Function, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void; +pub extern fn NativityLLVMCallSetAttributes(call: *LLVM.Value.Instruction.Call, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void; +// pub extern fn NativityLLVMFunctionAddAttributeKey(builder: *LLVM.Value.Constant.Function, attribute_key: LLVM.Attribute) void; pub extern fn NativityLLVMGetVoidType(context: *LLVM.Context) ?*LLVM.Type; pub extern fn NativityLLVMGetInlineAssembly(function_type: *LLVM.Type.Function, assembly_ptr: [*]const u8, assembly_len: usize, constraints_ptr: [*]const u8, constrains_len: usize, has_side_effects: bool, is_align_stack: bool, dialect: LLVM.Value.InlineAssembly.Dialect, can_throw: bool) ?*LLVM.Value.InlineAssembly; pub extern fn NativityLLVMBuilderCreateCall(builder: *LLVM.Builder, function_type: *LLVM.Type.Function, callee: *LLVM.Value, argument_ptr: [*]const *LLVM.Value, argument_count: usize, name_ptr: [*]const u8, name_len: usize, fp_math_tag: ?*LLVM.Metadata.Node) ?*LLVM.Value.Instruction.Call; @@ -143,6 +151,7 @@ pub extern fn NativityLLVMTargetCreateTargetMachine(target: *LLVM.Target, target pub extern fn NativityLLVMModuleSetTargetMachineDataLayout(module: *LLVM.Module, target_machine: *LLVM.Target.Machine) void; pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void; pub extern fn NativityLLVMModuleAddPassesToEmitFile(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, object_file_path_ptr: [*]const u8, object_file_path_len: usize, codegen_file_type: LLVM.CodeGenFileType, disable_verify: bool) bool; +pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void; pub extern fn NativityLLDLinkELF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool; pub extern fn NativityLLDLinkCOFF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool; pub extern fn NativityLLDLinkMachO(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool; diff --git a/bootstrap/frontend/lexer.zig b/bootstrap/frontend/lexer.zig index a968e22..66870bd 100644 --- a/bootstrap/frontend/lexer.zig +++ b/bootstrap/frontend/lexer.zig @@ -67,7 +67,7 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B var index: u32 = 0; var line_index: u32 = lexer.line_offset; - try token_buffer.ensure_with_capacity(allocator, len / 4); + try token_buffer.ensure_with_capacity(allocator, len / 3); // logln(.lexer, .end, "START LEXER - TOKEN OFFSET: {} - LINE OFFSET: {}", .{ Token.unwrap(lexer.offset), lexer.line_offset }); diff --git a/bootstrap/frontend/parser.zig b/bootstrap/frontend/parser.zig index c98616e..3cd3e85 100644 --- a/bootstrap/frontend/parser.zig +++ b/bootstrap/frontend/parser.zig @@ -420,13 +420,23 @@ const Analyzer = struct { if (data_structures.byte_equal(identifier_name, enum_field.name)) { const attribute = @field(Compilation.Function.Attribute, enum_field.name); const attribute_node = switch (attribute) { - .naked, - => try analyzer.addNode(.{ + .naked => try analyzer.addNode(.{ .id = @field(Node.Id, "function_attribute_" ++ @tagName(attribute)), .token = identifier, .left = .null, .right = .null, }), + .cc => try analyzer.addNode(.{ + .id = .function_attribute_cc, + .token = identifier, + .left = b: { + _ = try analyzer.expectToken(.operator_left_parenthesis); + const cc = try analyzer.expression(); + _ = try analyzer.expectToken(.operator_right_parenthesis); + break :b cc; + }, + .right = .null, + }), else => |t| @panic(@tagName(t)), }; break attribute_node; @@ -462,7 +472,11 @@ const Analyzer = struct { var list = UnpinnedArray(Node.Index){}; while (analyzer.peekToken() != end_token) { - const identifier = try analyzer.expectToken(.identifier); + const identifier_token = analyzer.token_i; + switch (analyzer.peekToken()) { + .identifier, .discard => analyzer.consumeToken(), + else => |t| @panic(@tagName(t)), + } _ = try analyzer.expectToken(.operator_colon); const type_expression = try analyzer.typeExpression(); @@ -472,7 +486,7 @@ const Analyzer = struct { try list.append(analyzer.my_allocator, try analyzer.addNode(.{ .id = .argument_declaration, - .token = identifier, + .token = identifier_token, .left = type_expression, .right = Node.Index.null, })); diff --git a/bootstrap/library.zig b/bootstrap/library.zig index 4b98986..c52e91b 100644 --- a/bootstrap/library.zig +++ b/bootstrap/library.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const os = builtin.os.tag; const arch = builtin.cpu.arch; +const page_size = std.mem.page_size; pub fn assert(ok: bool) void { if (!ok) unreachable; @@ -257,7 +258,7 @@ pub fn MyHashMap(comptime K: type, comptime V: type) type { .Slice => byte_equal(k, key), else => k == key, }, - .Struct => equal(k, key), + .Struct, .Array => equal(k, key), else => k == key, }; @@ -331,7 +332,6 @@ pub fn enumFromString(comptime E: type, string: []const u8) ?E { } else null; } -const page_size = std.mem.page_size; extern fn pthread_jit_write_protect_np(enabled: bool) void; pub fn allocate_virtual_memory(size: usize, flags: packed struct { @@ -353,10 +353,10 @@ pub fn allocate_virtual_memory(size: usize, flags: packed struct { .linux => u32, .macos => c_int, else => @compileError("OS not supported"), - } = if (flags.executable) std.os.PROT.EXEC else 0; - const protection_flags: u32 = @intCast(std.os.PROT.READ | std.os.PROT.WRITE | execute_flag); + } = if (flags.executable) std.posix.PROT.EXEC else 0; + const protection_flags: u32 = @intCast(std.posix.PROT.READ | std.posix.PROT.WRITE | execute_flag); - const result = try std.os.mmap(null, size, protection_flags, .{ + const result = try std.posix.mmap(null, size, protection_flags, .{ .TYPE = .PRIVATE, .ANONYMOUS = true, }, -1, 0); @@ -372,13 +372,13 @@ pub fn allocate_virtual_memory(size: usize, flags: packed struct { }; } -pub fn free_virtual_memory(slice: []align(0x1000) const u8) void { +pub fn free_virtual_memory(slice: []align(page_size) const u8) void { switch (os) { .windows => { std.os.windows.VirtualFree(slice.ptr, slice.len, std.os.windows.MEM_RELEASE); }, else => { - std.os.munmap(slice); + std.posix.munmap(slice); }, } } @@ -726,7 +726,7 @@ pub fn span(ptr: [*:0]const u8) [:0]const u8 { pub fn last(bytes: []const u8, byte: u8) ?usize { var i = bytes.len; - while (i > 0) { + while (i > 0) { i -= 1; if (bytes[i] == byte) { @@ -736,3 +736,8 @@ pub fn last(bytes: []const u8, byte: u8) ?usize { return null; } + +pub fn align_forward(value: u64, alignment: u64) u64 { + const mask = alignment - 1; + return (value + mask) & ~mask; +} diff --git a/bootstrap/main.zig b/bootstrap/main.zig index f2eeb6c..38bce38 100644 --- a/bootstrap/main.zig +++ b/bootstrap/main.zig @@ -55,7 +55,7 @@ pub fn entry_point(arguments: [][*:0]u8) !void { return error.InvalidInput; } - if (std.process.can_execv and std.os.getenvZ(env_detecting_libc_paths) != null) { + if (std.process.can_execv and std.posix.getenvZ(env_detecting_libc_paths) != null) { todo(); } diff --git a/build.zig b/build.zig index ee4401b..ae86107 100644 --- a/build.zig +++ b/build.zig @@ -1,14 +1,32 @@ const std = @import("std"); const assert = std.debug.assert; +const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const os = builtin.os.tag; + +fn discover_brew_prefix(b: *std.Build, library_name: []const u8) ![]const u8 { + assert(os == .macos); + const result = try std.ChildProcess.run(.{ + .allocator = b.allocator, + .argv = &.{ "brew", "--prefix", library_name }, + }); + + var i = result.stdout.len - 1; + while (result.stdout[i] == '\n' or result.stdout[i] == ' ') { + i -= 1; + } + const trimmed_path = result.stdout[0 .. i + 1]; + return trimmed_path; +} pub fn build(b: *std.Build) !void { const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false; const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false; const is_ci = self_hosted_ci or third_party_ci; - const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or @import("builtin").os.tag == .macos; + const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or os == .macos; const native_target = b.resolveTargetQuery(.{}); const optimization = b.standardOptimizeOption(.{}); - const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse false; + const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse true; const compiler_options = b.addOptions(); compiler_options.addOption(bool, "print_stack_trace", print_stack_trace); @@ -21,7 +39,7 @@ pub fn build(b: *std.Build) !void { }); var target_query = b.standardTargetOptionsQueryOnly(.{}); - const abi = b.option(std.Target.Abi, "abi", "This option modifies the ABI used for the compiler") orelse if (static) switch (native_target.result.os.tag) { + const abi = b.option(std.Target.Abi, "abi", "This option modifies the ABI used for the compiler") orelse if (static) switch (os) { else => target_query.abi, .linux => b: { const os_release = try std.fs.cwd().readFileAlloc(b.allocator, "/etc/os-release", 0xffff); @@ -86,8 +104,249 @@ pub fn build(b: *std.Build) !void { compiler.linkLibC(); + const zstd = if (target.result.os.tag == .windows) "zstd.lib" else "libzstd.a"; + + const static_llvm_libraries = [_][]const u8{ + "libLLVMAArch64AsmParser.a", + "libLLVMAArch64CodeGen.a", + "libLLVMAArch64Desc.a", + "libLLVMAArch64Disassembler.a", + "libLLVMAArch64Info.a", + "libLLVMAArch64Utils.a", + "libLLVMAggressiveInstCombine.a", + "libLLVMAMDGPUAsmParser.a", + "libLLVMAMDGPUCodeGen.a", + "libLLVMAMDGPUDesc.a", + "libLLVMAMDGPUDisassembler.a", + "libLLVMAMDGPUInfo.a", + "libLLVMAMDGPUTargetMCA.a", + "libLLVMAMDGPUUtils.a", + "libLLVMAnalysis.a", + "libLLVMARMAsmParser.a", + "libLLVMARMCodeGen.a", + "libLLVMARMDesc.a", + "libLLVMARMDisassembler.a", + "libLLVMARMInfo.a", + "libLLVMARMUtils.a", + "libLLVMAsmParser.a", + "libLLVMAsmPrinter.a", + "libLLVMAVRAsmParser.a", + "libLLVMAVRCodeGen.a", + "libLLVMAVRDesc.a", + "libLLVMAVRDisassembler.a", + "libLLVMAVRInfo.a", + "libLLVMBinaryFormat.a", + "libLLVMBitReader.a", + "libLLVMBitstreamReader.a", + "libLLVMBitWriter.a", + "libLLVMBPFAsmParser.a", + "libLLVMBPFCodeGen.a", + "libLLVMBPFDesc.a", + "libLLVMBPFDisassembler.a", + "libLLVMBPFInfo.a", + "libLLVMCFGuard.a", + "libLLVMCFIVerify.a", + "libLLVMCodeGen.a", + "libLLVMCodeGenTypes.a", + "libLLVMCore.a", + "libLLVMCoroutines.a", + "libLLVMCoverage.a", + "libLLVMDebugInfoBTF.a", + "libLLVMDebugInfoCodeView.a", + "libLLVMDebuginfod.a", + "libLLVMDebugInfoDWARF.a", + "libLLVMDebugInfoGSYM.a", + "libLLVMDebugInfoLogicalView.a", + "libLLVMDebugInfoMSF.a", + "libLLVMDebugInfoPDB.a", + "libLLVMDemangle.a", + "libLLVMDiff.a", + "libLLVMDlltoolDriver.a", + "libLLVMDWARFLinker.a", + "libLLVMDWARFLinkerParallel.a", + "libLLVMDWP.a", + "libLLVMExecutionEngine.a", + "libLLVMExtensions.a", + "libLLVMFileCheck.a", + "libLLVMFrontendHLSL.a", + "libLLVMFrontendOpenACC.a", + "libLLVMFrontendOpenMP.a", + "libLLVMFuzzerCLI.a", + "libLLVMFuzzMutate.a", + "libLLVMGlobalISel.a", + "libLLVMHexagonAsmParser.a", + "libLLVMHexagonCodeGen.a", + "libLLVMHexagonDesc.a", + "libLLVMHexagonDisassembler.a", + "libLLVMHexagonInfo.a", + "libLLVMInstCombine.a", + "libLLVMInstrumentation.a", + "libLLVMInterfaceStub.a", + "libLLVMInterpreter.a", + "libLLVMipo.a", + "libLLVMIRPrinter.a", + "libLLVMIRReader.a", + "libLLVMJITLink.a", + "libLLVMLanaiAsmParser.a", + "libLLVMLanaiCodeGen.a", + "libLLVMLanaiDesc.a", + "libLLVMLanaiDisassembler.a", + "libLLVMLanaiInfo.a", + "libLLVMLibDriver.a", + "libLLVMLineEditor.a", + "libLLVMLinker.a", + "libLLVMLoongArchAsmParser.a", + "libLLVMLoongArchCodeGen.a", + "libLLVMLoongArchDesc.a", + "libLLVMLoongArchDisassembler.a", + "libLLVMLoongArchInfo.a", + "libLLVMLTO.a", + "libLLVMMC.a", + "libLLVMMCA.a", + "libLLVMMCDisassembler.a", + "libLLVMMCJIT.a", + "libLLVMMCParser.a", + "libLLVMMipsAsmParser.a", + "libLLVMMipsCodeGen.a", + "libLLVMMipsDesc.a", + "libLLVMMipsDisassembler.a", + "libLLVMMipsInfo.a", + "libLLVMMIRParser.a", + "libLLVMMSP430AsmParser.a", + "libLLVMMSP430CodeGen.a", + "libLLVMMSP430Desc.a", + "libLLVMMSP430Disassembler.a", + "libLLVMMSP430Info.a", + "libLLVMNVPTXCodeGen.a", + "libLLVMNVPTXDesc.a", + "libLLVMNVPTXInfo.a", + "libLLVMObjCARCOpts.a", + "libLLVMObjCopy.a", + "libLLVMObject.a", + "libLLVMObjectYAML.a", + "libLLVMOption.a", + "libLLVMOrcJIT.a", + "libLLVMOrcShared.a", + "libLLVMOrcTargetProcess.a", + "libLLVMPasses.a", + "libLLVMPowerPCAsmParser.a", + "libLLVMPowerPCCodeGen.a", + "libLLVMPowerPCDesc.a", + "libLLVMPowerPCDisassembler.a", + "libLLVMPowerPCInfo.a", + "libLLVMProfileData.a", + "libLLVMRemarks.a", + "libLLVMRISCVAsmParser.a", + "libLLVMRISCVCodeGen.a", + "libLLVMRISCVDesc.a", + "libLLVMRISCVDisassembler.a", + "libLLVMRISCVInfo.a", + "libLLVMRISCVTargetMCA.a", + "libLLVMRuntimeDyld.a", + "libLLVMScalarOpts.a", + "libLLVMSelectionDAG.a", + "libLLVMSparcAsmParser.a", + "libLLVMSparcCodeGen.a", + "libLLVMSparcDesc.a", + "libLLVMSparcDisassembler.a", + "libLLVMSparcInfo.a", + "libLLVMSupport.a", + "libLLVMSymbolize.a", + "libLLVMSystemZAsmParser.a", + "libLLVMSystemZCodeGen.a", + "libLLVMSystemZDesc.a", + "libLLVMSystemZDisassembler.a", + "libLLVMSystemZInfo.a", + "libLLVMTableGen.a", + "libLLVMTableGenCommon.a", + "libLLVMTableGenGlobalISel.a", + "libLLVMTarget.a", + "libLLVMTargetParser.a", + "libLLVMTextAPI.a", + "libLLVMTransformUtils.a", + "libLLVMVEAsmParser.a", + "libLLVMVECodeGen.a", + "libLLVMVectorize.a", + "libLLVMVEDesc.a", + "libLLVMVEDisassembler.a", + "libLLVMVEInfo.a", + "libLLVMWebAssemblyAsmParser.a", + "libLLVMWebAssemblyCodeGen.a", + "libLLVMWebAssemblyDesc.a", + "libLLVMWebAssemblyDisassembler.a", + "libLLVMWebAssemblyInfo.a", + "libLLVMWebAssemblyUtils.a", + "libLLVMWindowsDriver.a", + "libLLVMWindowsManifest.a", + "libLLVMX86AsmParser.a", + "libLLVMX86CodeGen.a", + "libLLVMX86Desc.a", + "libLLVMX86Disassembler.a", + "libLLVMX86Info.a", + "libLLVMX86TargetMCA.a", + "libLLVMXCoreCodeGen.a", + "libLLVMXCoreDesc.a", + "libLLVMXCoreDisassembler.a", + "libLLVMXCoreInfo.a", + "libLLVMXRay.a", + //LLD + "liblldCOFF.a", + "liblldCommon.a", + "liblldELF.a", + "liblldMachO.a", + "liblldMinGW.a", + "liblldWasm.a", + // Zlib + "libz.a", + // Zstd + zstd, + // Clang + "libclangAnalysis.a", + "libclangAnalysisFlowSensitive.a", + "libclangAnalysisFlowSensitiveModels.a", + "libclangAPINotes.a", + "libclangARCMigrate.a", + "libclangAST.a", + "libclangASTMatchers.a", + "libclangBasic.a", + "libclangCodeGen.a", + "libclangCrossTU.a", + "libclangDependencyScanning.a", + "libclangDirectoryWatcher.a", + "libclangDriver.a", + "libclangDynamicASTMatchers.a", + "libclangEdit.a", + "libclangExtractAPI.a", + "libclangFormat.a", + "libclangFrontend.a", + "libclangFrontendTool.a", + "libclangHandleCXX.a", + "libclangHandleLLVM.a", + "libclangIndex.a", + "libclangIndexSerialization.a", + "libclangInterpreter.a", + "libclangLex.a", + "libclangParse.a", + "libclangRewrite.a", + "libclangRewriteFrontend.a", + "libclangSema.a", + "libclangSerialization.a", + "libclangStaticAnalyzerCheckers.a", + "libclangStaticAnalyzerCore.a", + "libclangStaticAnalyzerFrontend.a", + "libclangSupport.a", + "libclangTooling.a", + "libclangToolingASTDiff.a", + "libclangToolingCore.a", + "libclangToolingInclusions.a", + "libclangToolingInclusionsStdlib.a", + "libclangToolingRefactoring.a", + "libclangToolingSyntax.a", + "libclangTransformer.a", + }; + if (static) { - compiler.linkage = .static; + if (os == .linux) compiler.linkage = .static; compiler.linkLibCpp(); const prefix = "nat/cache"; @@ -137,257 +396,11 @@ pub fn build(b: *std.Build) !void { compiler.addIncludePath(std.Build.LazyPath.relative(llvm_include_dir)); const llvm_lib_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_path, "/lib" }); - const zstd = if (target.result.os.tag == .windows) "zstd.lib" else "libzstd.a"; - - const llvm_libraries = [_][]const u8{ - "libLLVMAArch64AsmParser.a", - "libLLVMAArch64CodeGen.a", - "libLLVMAArch64Desc.a", - "libLLVMAArch64Disassembler.a", - "libLLVMAArch64Info.a", - "libLLVMAArch64Utils.a", - "libLLVMAggressiveInstCombine.a", - "libLLVMAMDGPUAsmParser.a", - "libLLVMAMDGPUCodeGen.a", - "libLLVMAMDGPUDesc.a", - "libLLVMAMDGPUDisassembler.a", - "libLLVMAMDGPUInfo.a", - "libLLVMAMDGPUTargetMCA.a", - "libLLVMAMDGPUUtils.a", - "libLLVMAnalysis.a", - "libLLVMARMAsmParser.a", - "libLLVMARMCodeGen.a", - "libLLVMARMDesc.a", - "libLLVMARMDisassembler.a", - "libLLVMARMInfo.a", - "libLLVMARMUtils.a", - "libLLVMAsmParser.a", - "libLLVMAsmPrinter.a", - "libLLVMAVRAsmParser.a", - "libLLVMAVRCodeGen.a", - "libLLVMAVRDesc.a", - "libLLVMAVRDisassembler.a", - "libLLVMAVRInfo.a", - "libLLVMBinaryFormat.a", - "libLLVMBitReader.a", - "libLLVMBitstreamReader.a", - "libLLVMBitWriter.a", - "libLLVMBPFAsmParser.a", - "libLLVMBPFCodeGen.a", - "libLLVMBPFDesc.a", - "libLLVMBPFDisassembler.a", - "libLLVMBPFInfo.a", - "libLLVMCFGuard.a", - "libLLVMCFIVerify.a", - "libLLVMCodeGen.a", - "libLLVMCodeGenTypes.a", - "libLLVMCore.a", - "libLLVMCoroutines.a", - "libLLVMCoverage.a", - "libLLVMDebugInfoBTF.a", - "libLLVMDebugInfoCodeView.a", - "libLLVMDebuginfod.a", - "libLLVMDebugInfoDWARF.a", - "libLLVMDebugInfoGSYM.a", - "libLLVMDebugInfoLogicalView.a", - "libLLVMDebugInfoMSF.a", - "libLLVMDebugInfoPDB.a", - "libLLVMDemangle.a", - "libLLVMDiff.a", - "libLLVMDlltoolDriver.a", - "libLLVMDWARFLinker.a", - "libLLVMDWARFLinkerParallel.a", - "libLLVMDWP.a", - "libLLVMExecutionEngine.a", - "libLLVMExtensions.a", - "libLLVMFileCheck.a", - "libLLVMFrontendHLSL.a", - "libLLVMFrontendOpenACC.a", - "libLLVMFrontendOpenMP.a", - "libLLVMFuzzerCLI.a", - "libLLVMFuzzMutate.a", - "libLLVMGlobalISel.a", - "libLLVMHexagonAsmParser.a", - "libLLVMHexagonCodeGen.a", - "libLLVMHexagonDesc.a", - "libLLVMHexagonDisassembler.a", - "libLLVMHexagonInfo.a", - "libLLVMInstCombine.a", - "libLLVMInstrumentation.a", - "libLLVMInterfaceStub.a", - "libLLVMInterpreter.a", - "libLLVMipo.a", - "libLLVMIRPrinter.a", - "libLLVMIRReader.a", - "libLLVMJITLink.a", - "libLLVMLanaiAsmParser.a", - "libLLVMLanaiCodeGen.a", - "libLLVMLanaiDesc.a", - "libLLVMLanaiDisassembler.a", - "libLLVMLanaiInfo.a", - "libLLVMLibDriver.a", - "libLLVMLineEditor.a", - "libLLVMLinker.a", - "libLLVMLoongArchAsmParser.a", - "libLLVMLoongArchCodeGen.a", - "libLLVMLoongArchDesc.a", - "libLLVMLoongArchDisassembler.a", - "libLLVMLoongArchInfo.a", - "libLLVMLTO.a", - "libLLVMMC.a", - "libLLVMMCA.a", - "libLLVMMCDisassembler.a", - "libLLVMMCJIT.a", - "libLLVMMCParser.a", - "libLLVMMipsAsmParser.a", - "libLLVMMipsCodeGen.a", - "libLLVMMipsDesc.a", - "libLLVMMipsDisassembler.a", - "libLLVMMipsInfo.a", - "libLLVMMIRParser.a", - "libLLVMMSP430AsmParser.a", - "libLLVMMSP430CodeGen.a", - "libLLVMMSP430Desc.a", - "libLLVMMSP430Disassembler.a", - "libLLVMMSP430Info.a", - "libLLVMNVPTXCodeGen.a", - "libLLVMNVPTXDesc.a", - "libLLVMNVPTXInfo.a", - "libLLVMObjCARCOpts.a", - "libLLVMObjCopy.a", - "libLLVMObject.a", - "libLLVMObjectYAML.a", - "libLLVMOption.a", - "libLLVMOrcJIT.a", - "libLLVMOrcShared.a", - "libLLVMOrcTargetProcess.a", - "libLLVMPasses.a", - "libLLVMPowerPCAsmParser.a", - "libLLVMPowerPCCodeGen.a", - "libLLVMPowerPCDesc.a", - "libLLVMPowerPCDisassembler.a", - "libLLVMPowerPCInfo.a", - "libLLVMProfileData.a", - "libLLVMRemarks.a", - "libLLVMRISCVAsmParser.a", - "libLLVMRISCVCodeGen.a", - "libLLVMRISCVDesc.a", - "libLLVMRISCVDisassembler.a", - "libLLVMRISCVInfo.a", - "libLLVMRISCVTargetMCA.a", - "libLLVMRuntimeDyld.a", - "libLLVMScalarOpts.a", - "libLLVMSelectionDAG.a", - "libLLVMSparcAsmParser.a", - "libLLVMSparcCodeGen.a", - "libLLVMSparcDesc.a", - "libLLVMSparcDisassembler.a", - "libLLVMSparcInfo.a", - "libLLVMSupport.a", - "libLLVMSymbolize.a", - "libLLVMSystemZAsmParser.a", - "libLLVMSystemZCodeGen.a", - "libLLVMSystemZDesc.a", - "libLLVMSystemZDisassembler.a", - "libLLVMSystemZInfo.a", - "libLLVMTableGen.a", - "libLLVMTableGenCommon.a", - "libLLVMTableGenGlobalISel.a", - "libLLVMTarget.a", - "libLLVMTargetParser.a", - "libLLVMTextAPI.a", - "libLLVMTransformUtils.a", - "libLLVMVEAsmParser.a", - "libLLVMVECodeGen.a", - "libLLVMVectorize.a", - "libLLVMVEDesc.a", - "libLLVMVEDisassembler.a", - "libLLVMVEInfo.a", - "libLLVMWebAssemblyAsmParser.a", - "libLLVMWebAssemblyCodeGen.a", - "libLLVMWebAssemblyDesc.a", - "libLLVMWebAssemblyDisassembler.a", - "libLLVMWebAssemblyInfo.a", - "libLLVMWebAssemblyUtils.a", - "libLLVMWindowsDriver.a", - "libLLVMWindowsManifest.a", - "libLLVMX86AsmParser.a", - "libLLVMX86CodeGen.a", - "libLLVMX86Desc.a", - "libLLVMX86Disassembler.a", - "libLLVMX86Info.a", - "libLLVMX86TargetMCA.a", - "libLLVMXCoreCodeGen.a", - "libLLVMXCoreDesc.a", - "libLLVMXCoreDisassembler.a", - "libLLVMXCoreInfo.a", - "libLLVMXRay.a", - //LLD - "liblldCOFF.a", - "liblldCommon.a", - "liblldELF.a", - "liblldMachO.a", - "liblldMinGW.a", - "liblldWasm.a", - // Zlib - "libz.a", - // Zstd - zstd, - // Clang - "libclangAnalysis.a", - "libclangAnalysisFlowSensitive.a", - "libclangAnalysisFlowSensitiveModels.a", - "libclangAPINotes.a", - "libclangARCMigrate.a", - "libclangAST.a", - "libclangASTMatchers.a", - "libclangBasic.a", - "libclangCodeGen.a", - "libclangCrossTU.a", - "libclangDependencyScanning.a", - "libclangDirectoryWatcher.a", - "libclangDriver.a", - "libclangDynamicASTMatchers.a", - "libclangEdit.a", - "libclangExtractAPI.a", - "libclangFormat.a", - "libclangFrontend.a", - "libclangFrontendTool.a", - "libclangHandleCXX.a", - "libclangHandleLLVM.a", - "libclangIndex.a", - "libclangIndexSerialization.a", - "libclangInterpreter.a", - "libclangLex.a", - "libclangParse.a", - "libclangRewrite.a", - "libclangRewriteFrontend.a", - "libclangSema.a", - "libclangSerialization.a", - "libclangStaticAnalyzerCheckers.a", - "libclangStaticAnalyzerCore.a", - "libclangStaticAnalyzerFrontend.a", - "libclangSupport.a", - "libclangTooling.a", - "libclangToolingASTDiff.a", - "libclangToolingCore.a", - "libclangToolingInclusions.a", - "libclangToolingInclusionsStdlib.a", - "libclangToolingRefactoring.a", - "libclangToolingSyntax.a", - "libclangTransformer.a", - }; - - for (llvm_libraries) |llvm_library| { + for (static_llvm_libraries) |llvm_library| { compiler.addObjectFile(std.Build.LazyPath.relative(try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library }))); } } else { - compiler.addObjectFile(.{ .cwd_relative = "/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../lib/libstdc++.so" }); - compiler.addIncludePath(.{ .cwd_relative = "/usr/include" }); - compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1" }); - compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu" }); - compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib" }); - compiler.linkSystemLibrary("LLVM"); + compiler.linkSystemLibrary("LLVM-17"); compiler.linkSystemLibrary("clang-cpp"); compiler.linkSystemLibrary("lldCommon"); compiler.linkSystemLibrary("lldCOFF"); @@ -395,6 +408,45 @@ pub fn build(b: *std.Build) !void { compiler.linkSystemLibrary("lldMachO"); compiler.linkSystemLibrary("lldWasm"); compiler.linkSystemLibrary("unwind"); + compiler.linkSystemLibrary("zlib"); + compiler.linkSystemLibrary("zstd"); + + switch (target.result.os.tag) { + .linux => { + compiler.addObjectFile(.{ .cwd_relative = "/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../lib/libstdc++.so" }); + compiler.addIncludePath(.{ .cwd_relative = "/usr/include" }); + compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1" }); + compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu" }); + compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib" }); + }, + .macos => { + compiler.linkLibCpp(); + + if (discover_brew_prefix(b, "llvm")) |llvm_prefix| { + const llvm_include_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/include" }); + const llvm_lib_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/lib" }); + compiler.addIncludePath(.{ .cwd_relative = llvm_include_path }); + compiler.addLibraryPath(.{ .cwd_relative = llvm_lib_path }); + } else |err| { + return err; + } + + if (discover_brew_prefix(b, "zstd")) |zstd_prefix| { + const zstd_lib_path = try std.mem.concat(b.allocator, u8, &.{ zstd_prefix, "/lib" }); + compiler.addLibraryPath(.{ .cwd_relative = zstd_lib_path }); + } else |err| { + return err; + } + + if (discover_brew_prefix(b, "zlib")) |zlib_prefix| { + const zlib_lib_path = try std.mem.concat(b.allocator, u8, &.{ zlib_prefix, "/lib" }); + compiler.addLibraryPath(.{ .cwd_relative = zlib_lib_path }); + } else |err| { + return err; + } + }, + else => |tag| @panic(@tagName(tag)), + } } const install_exe = b.addInstallArtifact(compiler, .{}); @@ -409,7 +461,7 @@ pub fn build(b: *std.Build) !void { const run_command = b.addSystemCommand(&.{compiler_exe_path}); run_command.step.dependOn(b.getInstallStep()); - const debug_command = switch (@import("builtin").os.tag) { + const debug_command = switch (os) { .linux => blk: { const result = b.addSystemCommand(&.{"gf2"}); result.addArgs(&.{ "-ex", "set disassembly-flavor intel" }); diff --git a/build/fetcher.zig b/build/fetcher.zig index 0ac2330..f820bf5 100644 --- a/build/fetcher.zig +++ b/build/fetcher.zig @@ -8,7 +8,7 @@ pub fn main() !void { var url_arg: ?[:0]const u8 = null; var prefix_arg: [:0]const u8 = "nat"; - const State = enum{ + const State = enum { none, prefix, url, @@ -16,7 +16,6 @@ pub fn main() !void { var state = State.none; - for (arguments[1..]) |argument| { switch (state) { .none => { @@ -43,8 +42,8 @@ pub fn main() !void { if (state != .none) return error.InvalidInput; const dot_index = std.mem.lastIndexOfScalar(u8, url, '.') orelse return error.InvalidInput; - const extension_string = url[dot_index + 1..]; - const Extension = enum{ + const extension_string = url[dot_index + 1 ..]; + const Extension = enum { xz, gz, zip, @@ -61,7 +60,7 @@ pub fn main() !void { }; defer http_client.deinit(); - var buffer: [16*1024]u8 = undefined; + var buffer: [16 * 1024]u8 = undefined; var request = try http_client.open(.GET, uri, .{ .server_header_buffer = &buffer, }); diff --git a/build/test_runner.zig b/build/test_runner.zig index 024af37..8ac9d7f 100644 --- a/build/test_runner.zig +++ b/build/test_runner.zig @@ -10,7 +10,7 @@ const TestError = error{ fail, }; -fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const []const u8{ +fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const []const u8 { var dir = try std.fs.cwd().openDir(path, .{ .iterate = true, }); @@ -48,11 +48,11 @@ fn runStandalone(allocator: Allocator, args: struct { for (test_names) |test_name| { std.debug.print("{s}... ", .{test_name}); - const source_file_path = try std.mem.concat(allocator, u8, &.{args.directory_path, "/", test_name, "/main.nat"}); + const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" }); const compile_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{"zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path}, + .argv = &.{ "zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }, }); ran_compilation_count += 1; @@ -77,11 +77,11 @@ fn runStandalone(allocator: Allocator, args: struct { } if (compilation_success) { - const test_path = try std.mem.concat(allocator, u8, &.{"nat/", test_name}); + const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ test_path }, + .argv = &.{test_path}, }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -107,8 +107,8 @@ fn runStandalone(allocator: Allocator, args: struct { } } - std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{args.group_name, total_compilation_count, failed_compilation_count}); - std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{args.group_name, total_test_count, ran_test_count, failed_test_count}); + std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{ args.group_name, total_compilation_count, failed_compilation_count }); + std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{ args.group_name, total_test_count, ran_test_count, failed_test_count }); if (failed_compilation_count > 0 or failed_test_count > 0) { return error.fail; @@ -129,11 +129,11 @@ fn runStandaloneTests(allocator: Allocator) !void { for (standalone_test_names) |standalone_test_name| { std.debug.print("{s}... ", .{standalone_test_name}); - const source_file_path = try std.mem.concat(allocator, u8, &.{standalone_test_dir_path, "/", standalone_test_name, "/main.nat"}); + const source_file_path = try std.mem.concat(allocator, u8, &.{ standalone_test_dir_path, "/", standalone_test_name, "/main.nat" }); const compile_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{"zig-out/bin/nat", "exe", "-main_source_file", source_file_path}, + .argv = &.{ "zig-out/bin/nat", "exe", "-main_source_file", source_file_path }, }); ran_compilation_count += 1; @@ -158,11 +158,11 @@ fn runStandaloneTests(allocator: Allocator) !void { } if (compilation_success) { - const test_path = try std.mem.concat(allocator, u8, &.{"nat/", standalone_test_name}); + const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", standalone_test_name }); const test_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ test_path }, + .argv = &.{test_path}, }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -188,8 +188,8 @@ fn runStandaloneTests(allocator: Allocator) !void { } } - std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{total_compilation_count, failed_compilation_count}); - std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{total_test_count, ran_test_count, failed_test_count}); + std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{ total_compilation_count, failed_compilation_count }); + std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ total_test_count, ran_test_count, failed_test_count }); if (failed_compilation_count > 0 or failed_test_count > 0) { return error.fail; @@ -203,7 +203,7 @@ fn runBuildTests(allocator: Allocator) !void { const test_names = try collectDirectoryDirEntries(allocator, test_dir_path); const test_dir_realpath = try std.fs.cwd().realpathAlloc(allocator, test_dir_path); const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, "zig-out/bin/nat"); - try std.os.chdir(test_dir_realpath); + try std.posix.chdir(test_dir_realpath); const total_compilation_count = test_names.len; var ran_compilation_count: usize = 0; @@ -215,12 +215,12 @@ fn runBuildTests(allocator: Allocator) !void { for (test_names) |test_name| { std.debug.print("{s}... ", .{test_name}); - try std.os.chdir(test_name); + try std.posix.chdir(test_name); const compile_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{compiler_realpath, "build"}, + .argv = &.{ compiler_realpath, "build" }, }); ran_compilation_count += 1; @@ -246,11 +246,11 @@ fn runBuildTests(allocator: Allocator) !void { } if (compilation_success) { - const test_path = try std.mem.concat(allocator, u8, &.{"nat/", test_name}); + const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ test_path }, + .argv = &.{test_path}, }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -275,13 +275,13 @@ fn runBuildTests(allocator: Allocator) !void { std.debug.print("\n", .{}); } - try std.os.chdir(test_dir_realpath); + try std.posix.chdir(test_dir_realpath); } - std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{total_compilation_count, failed_compilation_count}); - std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{total_test_count, ran_test_count, failed_test_count}); + std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{ total_compilation_count, failed_compilation_count }); + std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ total_test_count, ran_test_count, failed_test_count }); - try std.os.chdir(previous_cwd); + try std.posix.chdir(previous_cwd); if (failed_compilation_count > 0 or failed_test_count > 0) { return error.fail; @@ -289,24 +289,31 @@ fn runBuildTests(allocator: Allocator) !void { } pub fn main() !void { + var errors = false; var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const allocator = arena.allocator(); - try runStandalone(allocator, .{ + runStandalone(allocator, .{ .directory_path = "test/standalone", .group_name = "STANDALONE", .is_test = false, - }); - try runBuildTests(allocator); - try runStandalone(allocator, .{ + }) catch { + errors = true; + }; + runBuildTests(allocator) catch { + errors = true; + }; + runStandalone(allocator, .{ .directory_path = "test/tests", .group_name = "TEST EXECUTABLE", .is_test = true, - }); + }) catch { + errors = true; + }; std.debug.print("std... ", .{}); const result = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, .argv = &.{ "zig-out/bin/nat", "test", "-main_source_file", "lib/std/std.nat", "-name", "std" }, }); const compilation_result: TestError!bool = switch (result.term) { @@ -317,6 +324,7 @@ pub fn main() !void { }; const compilation_success = compilation_result catch b: { + errors = true; break :b false; }; @@ -330,9 +338,9 @@ pub fn main() !void { if (compilation_success) { const test_run = try std.ChildProcess.run(.{ - .allocator = allocator, + .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ "nat/std" }, + .argv = &.{"nat/std"}, }); const test_result: TestError!bool = switch (test_run.term) { .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, @@ -342,6 +350,7 @@ pub fn main() !void { }; const test_success = test_result catch b: { + errors = true; break :b false; }; std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"}); @@ -352,4 +361,8 @@ pub fn main() !void { std.debug.print("STDERR:\n\n{s}\n\n", .{test_run.stderr}); } } + + if (errors) { + return error.fail; + } } diff --git a/lib/std/builtin.nat b/lib/std/builtin.nat index b127fea..ec7aaac 100644 --- a/lib/std/builtin.nat +++ b/lib/std/builtin.nat @@ -16,6 +16,7 @@ const Abi = enum{ }; const CallingConvention = enum{ + c, system_v, }; diff --git a/lib/std/c.nat b/lib/std/c.nat index e69de29..382dfba 100644 --- a/lib/std/c.nat +++ b/lib/std/c.nat @@ -0,0 +1,83 @@ +const std = #import("std"); +const linux = std.os.linux; +const macos = std.os.macos; +const builtin = #import("builtin"); +const os = builtin.os; + +const Error = switch (os) { + .linux => linux.Error, + .macos => macos.Error, + else => #error("OS not supported"), +}; + +const unwrap_syscall = fn(syscall_result: ssize) Error!usize { + if (syscall_result == -1) { + const absolute_error: u64 = #cast(-syscall_result); + const error_int: u32 = #cast(absolute_error); + const err: Error = #cast(error_int); + return err; + } else { + const result: usize = #cast(syscall_result); + return result; + } +} + +const MapFlags = switch (os) { + .macos => bitfield(u32){ + shared: bool, + private: bool, + reserved: u2 = 0, + fixed: bool, + reserved0: bool = 0, + noreserve: bool, + reserved1: u2 = 0, + has_semaphore: bool, + no_cache: bool, + reserved2: u1 = 0, + anonymous: bool, + reserved3: u19 = 0, + }, + .linux => linux.MapFlags, + else => #error("OS not supported"), +}; + +const FileDescriptor = s32; +const ProcessId = s32; +const MAP_FAILED = 0xffffffffffffffff; + +const ProtectionFlags = bitfield(u32) { + read: bool, + write: bool, + execute: bool, +}; + +const get_protection_flags = fn(flags: std.os.ProtectionFlags) ProtectionFlags { + return ProtectionFlags{ + .read = flags.read, + .write = flags.write, + .execute = flags.execute, + }; +} + +const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{ + return MapFlags{ + .shared = false, + .private = true, + .fixed = false, + .noreserve = false, + .has_semaphore = false, + .no_cache = false, + .anonymous = true, + }; +} + +const write :: extern = fn cc(.c) (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize; +const exit :: extern = fn cc(.c) (exit_code: s32) noreturn; +const fork :: extern = fn cc(.c) () ProcessId; +const mmap :: extern = fn cc(.c) (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize; +const munmap :: extern = fn cc(.c) (address: [&]const u8, length: usize) s32; +const execve :: extern = fn cc(.c) (path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32; +const realpath :: extern = fn cc(.c) (path: [&:0]const u8, resolved_path: [&:0]u8) ?[&:0]u8; +const waitpid :: extern = fn cc(.c) (pid: ProcessId, status: &s32, flags: s32) s32; + +const _NSGetExecutablePath :: extern = fn cc(.c) (buffer: [&:0]u8, buffer_size: &u32) s32; diff --git a/lib/std/os.nat b/lib/std/os.nat index 9734634..8f215fa 100644 --- a/lib/std/os.nat +++ b/lib/std/os.nat @@ -15,7 +15,7 @@ const system = switch (link_libc) { true => c, false => switch (current) { .linux => linux, - .macos => macos, + .macos => c, .windows => windows, }, }; @@ -25,7 +25,7 @@ const unwrap_syscall = system.unwrap_syscall; const exit = fn(exit_code: s32) noreturn { switch (current) { .linux => _ = #syscall(#cast(linux.Syscall.exit_group), #cast(exit_code)), - .macos => macos.exit(exit_code), + .macos => system.exit(exit_code), .windows => windows.ExitProcess(#cast(exit_code)), } } @@ -46,7 +46,15 @@ const FileDescriptor = struct{ const read = fn(file_descriptor: FileDescriptor, bytes: []u8) ReadError!usize { if (bytes.len > 0) { switch (current) { - .linux, .macos => { + .linux => { + const len: usize = #min(max_file_operation_byte_count, bytes.len); + const syscall_result = system.read(file_descriptor, bytes); + const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) { + else => unreachable, + }; + return byte_count; + }, + .macos => { const len: usize = #min(max_file_operation_byte_count, bytes.len); const syscall_result = system.read(file_descriptor, bytes); const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) { @@ -67,7 +75,7 @@ const FileDescriptor = struct{ const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) WriteError!usize { switch (current) { - .linux, .macos => { + .linux => { const len: usize = #min(max_file_operation_byte_count, bytes.len); const syscall_result = system.write(file_descriptor.handle, bytes[0..len]); const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) { @@ -75,6 +83,14 @@ const FileDescriptor = struct{ }; return byte_count; }, + .macos => { + const len: usize = #min(max_file_operation_byte_count, bytes.len); + const syscall_result = system.write(file_descriptor.handle, bytes.ptr, bytes.len); + const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) { + else => return WriteError.write_failed, + }; + return byte_count; + }, else => #error("OS not supported"), } } @@ -122,8 +138,8 @@ const allocate_virtual_memory = fn(address: ?[&]u8, length: usize, general_prote .linux, .macos => { const syscall_result = system.mmap(address, length, protection_flags, map_flags, file_descriptor, offset); if (link_libc) { - if (result != system.MAP_FAILED) { - const result_address: [&]u8 = #cast(result); + if (syscall_result != system.MAP_FAILED) { + const result_address: [&]u8 = #cast(syscall_result); return result_address; } else { // TODO: @@ -147,12 +163,18 @@ const FreeError = error{ }; const free_virtual_memory = fn(bytes: []const u8) FreeError!void { switch (current) { - .linux, .macos => { + .linux => { const syscall_result = system.munmap(bytes); _ = unwrap_syscall(syscall_result) catch |err| switch (err) { else => unreachable, }; }, + .macos => { + const syscall_result = system.munmap(bytes.ptr, bytes.len); + _ = unwrap_syscall(syscall_result) catch |err| switch (err) { + else => unreachable, + }; + }, else => #error("OS not supported"), } } @@ -194,32 +216,31 @@ const current_executable_path = fn(buffer: [:0]u8) CurrentExecutablePath![]u8 { }; return bytes; }, - //.macos => { - // TODO: - //var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined; - //var symlink_path_len: u32 = symlink_path_buffer.len + 1; - //const ns_result = macos._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&); - //if (ns_result == 0) { - // const symlink_path = symlink_path_buffer[0..symlink_path_len]; - // const result = macos.realpath(symlink_path.ptr, buffer.ptr); - // if (result != null) { - // var i: usize = 0; - // while (i < buffer.len) { - // if (result[i] == 0) { - // break; - // } - // i += 1; - // } - // assert(i < buffer.len); + .macos => { + var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined; + var symlink_path_len: u32 = symlink_path_buffer.len + 1; + const ns_result = c._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&); + if (ns_result == 0) { + const symlink_path = symlink_path_buffer[0..symlink_path_len]; + if (c.realpath(symlink_path.ptr, buffer.ptr)) |result| { + var i: usize = 0; + while (i < buffer.len) { + if (result[i] == 0) { + break; + } + i += 1; + } + assert(i < buffer.len); - // return result[0..i]; - // } else { - // return null; - // } - //} else { - // return null; - //} - //}, + const r: []u8 = result[0..i]; + return r; + } else { + return CurrentExecutablePath.failed; + } + } else { + return CurrentExecutablePath.failed; + } + }, else => #error("OS not supported"), } } @@ -256,13 +277,11 @@ const ExecveError = error{ const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) ExecveError!noreturn { switch (current) { .linux, .macos => { - const syscall_result = linux.execve(path, argv, env); - const signed_syscall_result: ssize = #cast(syscall_result); - if (signed_syscall_result == -1) { - return ExecveError.execve_failed; - } else { - unreachable; - } + const syscall_result = system.execve(path, argv, env); + _ = unwrap_syscall(syscall_result) catch |err| switch (err) { + else => return ExecveError.execve_failed, + }; + unreachable; }, else => #error("OS not supported"), } @@ -410,7 +429,7 @@ const waitpid = fn(pid: Process.Id, flags: u32) WaitPidError!u32 { }, .macos => { var status: s32 = undefined; - if (macos.waitpid(pid, status.&, #cast(flags)) != -1) { + if (system.waitpid(pid, status.&, #cast(flags)) != -1) { const status_u: u32 = #cast(status); return status_u; } else { diff --git a/lib/std/os/macos.nat b/lib/std/os/macos.nat index 64fc50d..554d4e6 100644 --- a/lib/std/os/macos.nat +++ b/lib/std/os/macos.nat @@ -1,57 +1,337 @@ const std = #import("std"); -const FileDescriptor = s32; -const ProcessId = s32; -const MAP_FAILED = 0xffffffffffffffff; +const Error = error{ + /// No error occurred. + SUCCESS = 0, -const MapFlags = bitfield(u32){ - shared: bool, - private: bool, - reserved: u2 = 0, - fixed: bool, - reserved0: bool = 0, - noreserve: bool, - reserved1: u2 = 0, - has_semaphore: bool, - no_cache: bool, - reserved2: u1 = 0, - anonymous: bool, - reserved3: u19 = 0, + /// Operation not permitted + PERM = 1, + + /// No such file or directory + NOENT = 2, + + /// No such process + SRCH = 3, + + /// Interrupted system call + INTR = 4, + + /// Input/output error + IO = 5, + + /// Device not configured + NXIO = 6, + + /// Argument list too long + TOO_BIG = 7, + + /// Exec format error + NOEXEC = 8, + + /// Bad file descriptor + BADF = 9, + + /// No child processes + CHILD = 10, + + /// Resource deadlock avoided + DEADLK = 11, + + /// Cannot allocate memory + NOMEM = 12, + + /// Permission denied + ACCES = 13, + + /// Bad address + FAULT = 14, + + /// Block device required + NOTBLK = 15, + + /// Device / Resource busy + BUSY = 16, + + /// File exists + EXIST = 17, + + /// Cross-device link + XDEV = 18, + + /// Operation not supported by device + NODEV = 19, + + /// Not a directory + NOTDIR = 20, + + /// Is a directory + ISDIR = 21, + + /// Invalid argument + INVAL = 22, + + /// Too many open files in system + NFILE = 23, + + /// Too many open files + MFILE = 24, + + /// Inappropriate ioctl for device + NOTTY = 25, + + /// Text file busy + TXTBSY = 26, + + /// File too large + FBIG = 27, + + /// No space left on device + NOSPC = 28, + + /// Illegal seek + SPIPE = 29, + + /// Read-only file system + ROFS = 30, + + /// Too many links + MLINK = 31, + + /// Broken pipe + PIPE = 32, + + // math software + + /// Numerical argument out of domain + DOM = 33, + + /// Result too large + RANGE = 34, + + // non-blocking and interrupt i/o + + /// Resource temporarily unavailable + /// This is the same code used for `WOULDBLOCK`. + AGAIN = 35, + + /// Operation now in progress + INPROGRESS = 36, + + /// Operation already in progress + ALREADY = 37, + + // ipc/network software -- argument errors + + /// Socket operation on non-socket + NOTSOCK = 38, + + /// Destination address required + DESTADDRREQ = 39, + + /// Message too long + MSGSIZE = 40, + + /// Protocol wrong type for socket + PROTOTYPE = 41, + + /// Protocol not available + NOPROTOOPT = 42, + + /// Protocol not supported + PROTONOSUPPORT = 43, + + /// Socket type not supported + SOCKTNOSUPPORT = 44, + + /// Operation not supported + /// The same code is used for `NOTSUP`. + OPNOTSUPP = 45, + + /// Protocol family not supported + PFNOSUPPORT = 46, + + /// Address family not supported by protocol family + AFNOSUPPORT = 47, + + /// Address already in use + ADDRINUSE = 48, + /// Can't assign requested address + + // ipc/network software -- operational errors + ADDRNOTAVAIL = 49, + + /// Network is down + NETDOWN = 50, + + /// Network is unreachable + NETUNREACH = 51, + + /// Network dropped connection on reset + NETRESET = 52, + + /// Software caused connection abort + CONNABORTED = 53, + + /// Connection reset by peer + CONNRESET = 54, + + /// No buffer space available + NOBUFS = 55, + + /// Socket is already connected + ISCONN = 56, + + /// Socket is not connected + NOTCONN = 57, + + /// Can't send after socket shutdown + SHUTDOWN = 58, + + /// Too many references: can't splice + TOOMANYREFS = 59, + + /// Operation timed out + TIMEDOUT = 60, + + /// Connection refused + CONNREFUSED = 61, + + /// Too many levels of symbolic links + LOOP = 62, + + /// File name too long + NAMETOOLONG = 63, + + /// Host is down + HOSTDOWN = 64, + + /// No route to host + HOSTUNREACH = 65, + /// Directory not empty + + // quotas & mush + NOTEMPTY = 66, + + /// Too many processes + PROCLIM = 67, + + /// Too many users + USERS = 68, + /// Disc quota exceeded + + // Network File System + DQUOT = 69, + + /// Stale NFS file handle + STALE = 70, + + /// Too many levels of remote in path + REMOTE = 71, + + /// RPC struct is bad + BADRPC = 72, + + /// RPC version wrong + RPCMISMATCH = 73, + + /// RPC prog. not avail + PROGUNAVAIL = 74, + + /// Program version wrong + PROGMISMATCH = 75, + + /// Bad procedure for program + PROCUNAVAIL = 76, + + /// No locks available + NOLCK = 77, + + /// Function not implemented + NOSYS = 78, + + /// Inappropriate file type or format + FTYPE = 79, + + /// Authentication error + AUTH = 80, + + /// Need authenticator + NEEDAUTH = 81, + + // Intelligent device errors + + /// Device power is off + PWROFF = 82, + + /// Device error, e.g. paper out + DEVERR = 83, + + /// Value too large to be stored in data type + OVERFLOW = 84, + + // Program loading errors + + /// Bad executable + BADEXEC = 85, + + /// Bad CPU type in executable + BADARCH = 86, + + /// Shared library version mismatch + SHLIBVERS = 87, + + /// Malformed Macho file + BADMACHO = 88, + + /// Operation canceled + CANCELED = 89, + + /// Identifier removed + IDRM = 90, + + /// No message of desired type + NOMSG = 91, + + /// Illegal byte sequence + ILSEQ = 92, + + /// Attribute not found + NOATTR = 93, + + /// Bad message + BADMSG = 94, + + /// Reserved + MULTIHOP = 95, + + /// No message available on STREAM + NODATA = 96, + + /// Reserved + NOLINK = 97, + + /// No STREAM resources + NOSR = 98, + + /// Not a STREAM + NOSTR = 99, + + /// Protocol error + PROTO = 100, + + /// STREAM ioctl timeout + TIME = 101, + + /// No such policy registered + NOPOLICY = 103, + + /// State not recoverable + NOTRECOVERABLE = 104, + + /// Previous owner died + OWNERDEAD = 105, + + /// Interface output queue is full + QFULL = 106, }; -const ProtectionFlags = bitfield(u32) { - read: bool, - write: bool, - execute: bool, -}; - -const get_protection_flags = fn(flags: std.os.ProtectionFlags) ProtectionFlags { - return ProtectionFlags{ - .read = flags.read, - .write = flags.write, - .execute = flags.execute, - }; -} - -const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{ - return MapFlags{ - .shared = false, - .private = true, - .fixed = false, - .noreserve = false, - .has_semaphore = false, - .no_cache = false, - .anonymous = true, - }; -} - -const write :: extern = fn (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize; -const exit :: extern = fn (exit_code: s32) noreturn; -const fork :: extern = fn () ProcessId; -const mmap :: extern = fn (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize; -const munmap :: extern = fn (address: [&]const u8, length: usize) s32; -const execve :: extern = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32; -const realpath :: extern = fn(path: [&:0]const u8, resolved_path: [&:0]u8) [&:0]u8; -const waitpid :: extern = fn(pid: ProcessId, status: &s32, flags: s32) s32; - -const _NSGetExecutablePath :: extern = fn (buffer: [&:0]u8, buffer_size: &u32) s32; diff --git a/lib/std/start.nat b/lib/std/start.nat index 7a5474f..300c845 100644 --- a/lib/std/start.nat +++ b/lib/std/start.nat @@ -2,13 +2,13 @@ const std = #import("std"); const builtin = #import("builtin"); comptime { if (builtin.link_libc) { - _ = main; + #export(main); } else { - _ = _start; + #export(_start); } } -const _start :: export = fn naked() noreturn { +const _start = fn naked cc(.c) () noreturn { #asm(` xor ebp, ebp; mov rdi, rsp; @@ -21,7 +21,7 @@ var argument_count: usize = 0; var argument_values: [&]const [&:0]const u8 = undefined; var environment_values: [&:null]const ?[&:null]const u8 = undefined; -const start :: export = fn (argc_argv_address: usize) noreturn { +const start = fn cc(.c) (argc_argv_address: usize) noreturn { var argument_address_iterator = argc_argv_address; const argument_count_ptr: &usize = #cast(argument_address_iterator); argument_count = argument_count_ptr.@; @@ -35,7 +35,7 @@ const start :: export = fn (argc_argv_address: usize) noreturn { std.os.exit(0); } -const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 { +const main = fn cc(.c) (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 { const argc_u: u32 = #cast(argc); argument_count = argc_u; argument_values = argv; diff --git a/lib/std/std.nat b/lib/std/std.nat index 39934a3..eb7d7fb 100644 --- a/lib/std/std.nat +++ b/lib/std/std.nat @@ -12,6 +12,7 @@ test { const build = #import("build.nat"); const builtin = #import("builtin.nat"); const os = #import("os.nat"); +const c = #import("c.nat"); const start = #import("start.nat"); const testing = #import("testing.nat"); diff --git a/src/llvm/llvm.cpp b/src/llvm/llvm.cpp index f44451d..38adca8 100644 --- a/src/llvm/llvm.cpp +++ b/src/llvm/llvm.cpp @@ -288,6 +288,7 @@ extern "C" Function* NativityLLVMModuleGetFunction(Module& module, const char* n extern "C" void NativityLLVMFunctionAddAttributeKey(Function& function, Attribute::AttrKind attribute) { + static_assert(sizeof(Attribute) == sizeof(size_t)); function.addFnAttr(attribute); } @@ -357,6 +358,12 @@ extern "C" void NativityLLVMFunctionGetArguments(Function& function, Argument** } } +extern "C" Argument* NativityLLVMFunctionGetArgument(Function& function, unsigned index) +{ + auto* arg = function.getArg(index); + return arg; +} + extern "C" void NativityLLVMFunctionSetSubprogram(Function& function, DISubprogram* subprogram) { function.setSubprogram(subprogram); @@ -386,16 +393,21 @@ extern "C" ConstantInt* NativityLLVMConstantToInt(Constant* constant) return constant_int; } -extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile) +extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile, uint32_t alignment) { - auto* store = builder.CreateStore(value, pointer, is_volatile); + auto align = Align{alignment}; + auto* basic_block = builder.GetInsertBlock(); + auto* store = new StoreInst(value, pointer, is_volatile, align, + AtomicOrdering::NotAtomic, SyncScope::System, basic_block); return store; } -extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len) +extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len, uint32_t alignment) { auto name = StringRef(name_ptr, name_len); - auto* alloca = builder.CreateAlloca(type, address_space, array_size, name); + auto align = Align{ alignment }; + BasicBlock* insert_block = builder.GetInsertBlock(); + AllocaInst* alloca = new AllocaInst(type, address_space, array_size, align, name, insert_block); return alloca; } @@ -412,10 +424,13 @@ extern "C" Value* NativityLLVMBuilderCreateICmp(IRBuilder<>& builder, CmpInst::P return icmp; } -extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* value, bool is_volatile, const char* name_ptr, size_t name_len) +extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* pointer, bool is_volatile, const char* name_ptr, size_t name_len, uint32_t alignment) { + auto align = Align{alignment}; auto name = StringRef(name_ptr, name_len); - auto* load = builder.CreateLoad(type, value, is_volatile, name); + auto* basic_block = builder.GetInsertBlock(); + auto* load = new LoadInst(type, pointer, name, is_volatile, + align, AtomicOrdering::NotAtomic, SyncScope::System, basic_block); return load; } @@ -940,15 +955,61 @@ extern "C" bool NativityLLVMModuleAddPassesToEmitFile(Module& module, TargetMach return true; } -extern "C" bool NativityLLVMCompareTypes(Type* a, Type* b) +extern "C" Attribute NativityLLVMContextGetAttributeFromEnum(LLVMContext& context, Attribute::AttrKind kind, uint64_t value) { - if (auto* int_a = dyn_cast(a)) { - auto* int_b = dyn_cast(b); - assert(int_b); - auto a_bit_count = int_a->getBitWidth(); - auto b_bit_count = int_b->getBitWidth(); - assert(a_bit_count == b_bit_count); - } - - return a == b; + static_assert(sizeof(Attribute) == sizeof(uintptr_t)); + auto attribute = Attribute::get(context, kind, value); + return attribute; +} + +extern "C" Attribute NativityLLVMContextGetAttributeFromType(LLVMContext& context, Attribute::AttrKind kind, Type* type) +{ + static_assert(sizeof(Attribute) == sizeof(uintptr_t)); + auto attribute = Attribute::get(context, kind, type); + return attribute; +} + +extern "C" Attribute NativityLLVMContextGetAttributeFromString(LLVMContext& context, const char* kind_ptr, size_t kind_len, const char* value_ptr, size_t value_len) +{ + static_assert(sizeof(Attribute) == sizeof(uintptr_t)); + auto kind = StringRef(kind_ptr, kind_len); + auto value = StringRef(value_ptr, value_len); + auto attribute = Attribute::get(context, kind, value); + return attribute; +} + +extern "C" AttributeSet NativityLLVMContextGetAttributeSet(LLVMContext& context, const Attribute* attribute_ptr, size_t attribute_count) +{ + static_assert(sizeof(AttributeSet) == sizeof(uintptr_t)); + auto attributes = ArrayRef(attribute_ptr, attribute_count); + auto attribute_set = AttributeSet::get(context, attributes); + return attribute_set; +} + +extern "C" void NativityLLVMFunctionSetAttributes(Function& function, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count) +{ + auto parameter_attribute_sets = ArrayRef(parameter_attribute_set_ptr, parameter_attribute_set_count); + auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets); + function.setAttributes(attribute_list); +} + +extern "C" void NativityLLVMCallSetAttributes(CallInst& call, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count) +{ + auto parameter_attribute_sets = ArrayRef(parameter_attribute_set_ptr, parameter_attribute_set_count); + auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets); + call.setAttributes(attribute_list); +} + +extern "C" CallInst* NativityLLVMBuilderCreateMemcpy(IRBuilder<>& builder, Value* destination, uint32_t destination_alignment, Value* source, uint32_t source_alignment, uint64_t size, bool is_volatile) +{ + auto dst_alignment = MaybeAlign(destination_alignment); + auto src_alignment = MaybeAlign(source_alignment); + auto memcpy = builder.CreateMemCpy(destination, dst_alignment, source, src_alignment, size, is_volatile); + + return memcpy; +} + +extern "C" void NativityLLVMTypeAssertEqual(Type* a, Type* b) +{ + assert(a == b); } diff --git a/test/build/c-abi/.vscode/launch.json b/test/build/c-abi/.vscode/launch.json new file mode 100644 index 0000000..8f24839 --- /dev/null +++ b/test/build/c-abi/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "cppdbg", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/nat/c-abi", + "args": [], + "MIMode": "lldb", + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/test/build/c-abi/build.nat b/test/build/c-abi/build.nat index 6afe512..6a8f0db 100644 --- a/test/build/c-abi/build.nat +++ b/test/build/c-abi/build.nat @@ -10,7 +10,7 @@ const main = fn() *!void { }, .main_source_path = "main.nat", .name = "c-abi", - .c_source_files = .{ "foo.c" }.&, + .c_source_files = .{ "c.c" }.&, }; try executable.compile(); diff --git a/test/build/c-abi/c.c b/test/build/c-abi/c.c new file mode 100644 index 0000000..20a0e97 --- /dev/null +++ b/test/build/c-abi/c.c @@ -0,0 +1,5483 @@ +#include +#include +#include +#include +#include + +static void assert_or_panic(bool ok) { + if (!ok) { + __builtin_trap(); + } +} + +#ifndef memcpy +void* memcpy(void* dst_ptr, const void* src_ptr, size_t count) +{ + uint8_t* dst = (uint8_t*)dst_ptr; + uint8_t* src = (uint8_t*)src_ptr; + + for (size_t i = 0; i < count; i += 1) + { + dst[i] = src[i]; + } + + return dst; +} +#endif + +#ifndef memset +void* memset(void* dst_ptr, int value, size_t count) +{ + uint8_t ch = (uint8_t) value; + uint8_t* ptr = (uint8_t*) dst_ptr; + for (size_t i = 0; i < count; i += 1) { + ptr[i] = ch; + } + + return ptr; +} +#endif + +#if defined __powerpc__ && !defined _ARCH_PPC64 +# define ZIG_PPC32 +#endif + +#ifdef __riscv +# ifdef _ILP32 +# define ZIG_RISCV32 +# else +# define ZIG_RISCV64 +# endif +#endif + +#if defined(__aarch64__) && defined(__linux__) +// TODO: https://github.com/ziglang/zig/issues/14908 +#define ZIG_BUG_14908 +#endif + +#ifdef __i386__ +# define ZIG_NO_I128 +#endif + +#ifdef __arm__ +# define ZIG_NO_I128 +#endif + +#ifdef __mips__ +# define ZIG_NO_I128 +#endif + +#ifdef ZIG_PPC32 +# define ZIG_NO_I128 +#endif + +#ifdef ZIG_RISCV32 +# define ZIG_NO_I128 +#endif + +#ifdef __i386__ +# define ZIG_NO_COMPLEX +#endif + +#ifdef __mips__ +# define ZIG_NO_COMPLEX +#endif + +#ifdef __arm__ +# define ZIG_NO_COMPLEX +#endif + +#ifdef __powerpc__ +# define ZIG_NO_COMPLEX +#endif + +#ifdef __riscv +# define ZIG_NO_COMPLEX +#endif + +#ifdef __x86_64__ +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __i386__ +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __mips__ +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __riscv +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __wasm__ +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __powerpc__ +#define ZIG_NO_RAW_F16 +#endif + +#ifdef __aarch64__ +#define ZIG_NO_F128 +#endif + +#ifdef __arm__ +#define ZIG_NO_F128 +#endif + +#ifdef __mips__ +#define ZIG_NO_F128 +#endif + +#ifdef __riscv +#define ZIG_NO_F128 +#endif + +#ifdef __powerpc__ +#define ZIG_NO_F128 +#endif + +#ifdef __APPLE__ +#define ZIG_NO_F128 +#endif + +#ifndef ZIG_NO_I128 +// struct i128 { +// __int128 value; +// }; + +// struct u128 { +// unsigned __int128 value; +// }; +#endif + +void nat_u8(uint8_t); +void nat_u16(uint16_t); +void nat_u32(uint32_t); +void nat_u64(uint64_t); +// #ifndef ZIG_NO_I128 +// void nat_struct_u128(struct u128); +// #endif +void nat_s8(int8_t); +void nat_s16(int16_t); +void nat_s32(int32_t); +void nat_s64(int64_t); +// #ifndef ZIG_NO_I128 +// void nat_struct_i128(struct i128); +// #endif +void nat_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t); + +// void nat_f32(float); +// void nat_f64(double); +// void nat_longdouble(long double); +// void nat_fivesfloats(float, float, float, float, float); + +bool nat_ret_bool(); +uint8_t nat_ret_u8(); +uint16_t nat_ret_u16(); +uint32_t nat_ret_u32(); +uint64_t nat_ret_u64(); +int8_t nat_ret_s8(); +int16_t nat_ret_s16(); +int32_t nat_ret_s32(); +int64_t nat_ret_s64(); + +void nat_ptr(void *); + +void nat_bool(bool); + +// Note: These two functions match the signature of __mulsc3 and __muldc3 in compiler-rt (and libgcc) +// float complex nat_cmultf_comp(float a_r, float a_i, float b_r, float b_i); +// double complex nat_cmultd_comp(double a_r, double a_i, double b_r, double b_i); +// +// float complex nat_cmultf(float complex a, float complex b); +// double complex nat_cmultd(double complex a, double complex b); + +struct Struct_u64_u64 { + uint64_t a; + uint64_t b; +}; + +struct Struct_u64_u64 nat_ret_struct_u64_u64(void); + +void nat_struct_u64_u64_0(struct Struct_u64_u64); +void nat_struct_u64_u64_1(size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_2(size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_3(size_t, size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_4(size_t, size_t, size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_5(size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_6(size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_7(size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64); +void nat_struct_u64_u64_8(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64); + +struct Struct_u64_u64 c_ret_struct_u64_u64(void) { + return (struct Struct_u64_u64){ 21, 22 }; +} + +void c_struct_u64_u64_0(struct Struct_u64_u64 s) { + assert_or_panic(s.a == 23); + assert_or_panic(s.b == 24); +} +void c_struct_u64_u64_1(size_t a, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 25); + assert_or_panic(s.b == 26); +} +void c_struct_u64_u64_2(size_t a , size_t b, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 27); + assert_or_panic(s.b == 28); +} +void c_struct_u64_u64_3(size_t a, size_t b, size_t c, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 29); + assert_or_panic(s.b == 30); +} +void c_struct_u64_u64_4(size_t a, size_t b, size_t c, size_t d, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 31); + assert_or_panic(s.b == 32); +} +void c_struct_u64_u64_5(size_t a, size_t b, size_t c, size_t d, size_t e, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 33); + assert_or_panic(s.b == 34); +} +void c_struct_u64_u64_6(size_t a, size_t b, size_t c, size_t d, size_t e, size_t f, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 35); + assert_or_panic(s.b == 36); +} +void c_struct_u64_u64_7(size_t a, size_t b, size_t c, size_t d, size_t e, size_t f, size_t g, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 37); + assert_or_panic(s.b == 38); +} +void c_struct_u64_u64_8(size_t a, size_t b, size_t c, size_t d, size_t e, size_t f, size_t g, size_t h, struct Struct_u64_u64 s) { + assert_or_panic(s.a == 39); + assert_or_panic(s.b == 40); +} + +struct BigStruct { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; + uint8_t e; +}; + +void nat_big_struct(struct BigStruct); + +union BigUnion { + struct BigStruct a; +}; + +void nat_big_union(union BigUnion); + +struct SmallStructInts { + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; +}; + +void nat_small_struct_ints(struct SmallStructInts); +struct SmallStructInts nat_ret_small_struct_ints(); + +struct MedStructInts { + int32_t x; + int32_t y; + int32_t z; +}; + +void nat_med_struct_ints(struct MedStructInts); +struct MedStructInts nat_ret_med_struct_ints(); + +struct MedStructMixed { + uint32_t a; + float b; + float c; + uint32_t d; +}; + +void nat_med_struct_mixed(struct MedStructMixed); +struct MedStructMixed nat_ret_med_struct_mixed(); + +void nat_small_packed_struct(uint8_t); +// #ifndef ZIG_NO_I128 +// void nat_big_packed_struct(__int128); +// #endif + +struct SplitStructInts { + uint64_t a; + uint8_t b; + uint32_t c; +}; +void nat_split_struct_ints(struct SplitStructInts); + +struct SplitStructMixed { + uint64_t a; + uint8_t b; + float c; +}; +void nat_split_struct_mixed(struct SplitStructMixed); +struct SplitStructMixed nat_ret_split_struct_mixed(); + +struct BigStruct nat_big_struct_both(struct BigStruct); + +typedef float Vector2Float __attribute__((ext_vector_type(2))); +typedef float Vector4Float __attribute__((ext_vector_type(4))); + +void c_vector_2_float(Vector2Float vec) { + assert_or_panic(vec[0] == 1.0); + assert_or_panic(vec[1] == 2.0); +} + +void c_vector_4_float(Vector4Float vec) { + assert_or_panic(vec[0] == 1.0); + assert_or_panic(vec[1] == 2.0); + assert_or_panic(vec[2] == 3.0); + assert_or_panic(vec[3] == 4.0); +} + +Vector2Float c_ret_vector_2_float(void) { + return (Vector2Float){ + 1.0, + 2.0, + }; +} +Vector4Float c_ret_vector_4_float(void) { + return (Vector4Float){ + 1.0, + 2.0, + 3.0, + 4.0, + }; +} + +#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) || defined(__wasm__) + +typedef bool Vector2Bool __attribute__((ext_vector_type(2))); +typedef bool Vector4Bool __attribute__((ext_vector_type(4))); +typedef bool Vector8Bool __attribute__((ext_vector_type(8))); +typedef bool Vector16Bool __attribute__((ext_vector_type(16))); +typedef bool Vector32Bool __attribute__((ext_vector_type(32))); +typedef bool Vector64Bool __attribute__((ext_vector_type(64))); +typedef bool Vector128Bool __attribute__((ext_vector_type(128))); +typedef bool Vector256Bool __attribute__((ext_vector_type(256))); +typedef bool Vector512Bool __attribute__((ext_vector_type(512))); + +void c_vector_2_bool(Vector2Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); +} + +void c_vector_4_bool(Vector4Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == true); +} + +void c_vector_8_bool(Vector8Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); +} + +void c_vector_16_bool(Vector16Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); +} + +void c_vector_32_bool(Vector32Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == true); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == true); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == true); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == false); +} + +void c_vector_64_bool(Vector64Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == true); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == false); + assert_or_panic(vec[23] == true); + assert_or_panic(vec[24] == true); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == true); + assert_or_panic(vec[34] == false); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == false); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == false); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == true); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == true); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == false); + assert_or_panic(vec[53] == true); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == true); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == false); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == true); + assert_or_panic(vec[63] == false); +} + +void c_vector_128_bool(Vector128Bool vec) { + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == true); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == true); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == false); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == false); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == true); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == true); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == true); + assert_or_panic(vec[59] == false); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == true); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == true); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == false); + assert_or_panic(vec[69] == true); + assert_or_panic(vec[70] == false); + assert_or_panic(vec[71] == false); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == false); + assert_or_panic(vec[75] == true); + assert_or_panic(vec[76] == true); + assert_or_panic(vec[77] == true); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == false); + assert_or_panic(vec[83] == false); + assert_or_panic(vec[84] == true); + assert_or_panic(vec[85] == false); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == false); + assert_or_panic(vec[88] == true); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == false); + assert_or_panic(vec[91] == false); + assert_or_panic(vec[92] == true); + assert_or_panic(vec[93] == true); + assert_or_panic(vec[94] == true); + assert_or_panic(vec[95] == true); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == false); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == false); + assert_or_panic(vec[100] == false); + assert_or_panic(vec[101] == true); + assert_or_panic(vec[102] == false); + assert_or_panic(vec[103] == false); + assert_or_panic(vec[104] == false); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == true); + assert_or_panic(vec[108] == true); + assert_or_panic(vec[109] == true); + assert_or_panic(vec[110] == true); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == true); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == true); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == true); + assert_or_panic(vec[119] == false); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == false); + assert_or_panic(vec[122] == true); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == true); + assert_or_panic(vec[126] == true); + assert_or_panic(vec[127] == true); +} + +// WASM: The following vector functions define too many Wasm locals for wasmtime in debug mode and are therefore disabled for the wasm target. +#if !defined(__wasm__) + +void c_vector_256_bool(Vector256Bool vec) { + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == false); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == false); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == false); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == false); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == true); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == false); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == true); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == false); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == false); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == true); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == true); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == false); + assert_or_panic(vec[67] == false); + assert_or_panic(vec[68] == false); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == false); + assert_or_panic(vec[74] == false); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == true); + assert_or_panic(vec[77] == false); + assert_or_panic(vec[78] == true); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == true); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == false); + assert_or_panic(vec[85] == true); + assert_or_panic(vec[86] == true); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == true); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == true); + assert_or_panic(vec[92] == false); + assert_or_panic(vec[93] == true); + assert_or_panic(vec[94] == true); + assert_or_panic(vec[95] == false); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == true); + assert_or_panic(vec[98] == true); + assert_or_panic(vec[99] == false); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == false); + assert_or_panic(vec[102] == false); + assert_or_panic(vec[103] == true); + assert_or_panic(vec[104] == false); + assert_or_panic(vec[105] == true); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == true); + assert_or_panic(vec[108] == true); + assert_or_panic(vec[109] == true); + assert_or_panic(vec[110] == false); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == true); + assert_or_panic(vec[115] == true); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == true); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == false); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == false); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == false); + assert_or_panic(vec[125] == true); + assert_or_panic(vec[126] == true); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == true); + assert_or_panic(vec[129] == false); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == true); + assert_or_panic(vec[132] == false); + assert_or_panic(vec[133] == false); + assert_or_panic(vec[134] == true); + assert_or_panic(vec[135] == false); + assert_or_panic(vec[136] == false); + assert_or_panic(vec[137] == true); + assert_or_panic(vec[138] == false); + assert_or_panic(vec[139] == true); + assert_or_panic(vec[140] == false); + assert_or_panic(vec[141] == true); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == true); + assert_or_panic(vec[144] == true); + assert_or_panic(vec[145] == false); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == false); + assert_or_panic(vec[148] == false); + assert_or_panic(vec[149] == false); + assert_or_panic(vec[150] == true); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == true); + assert_or_panic(vec[153] == true); + assert_or_panic(vec[154] == true); + assert_or_panic(vec[155] == false); + assert_or_panic(vec[156] == true); + assert_or_panic(vec[157] == false); + assert_or_panic(vec[158] == false); + assert_or_panic(vec[159] == false); + assert_or_panic(vec[160] == true); + assert_or_panic(vec[161] == true); + assert_or_panic(vec[162] == false); + assert_or_panic(vec[163] == true); + assert_or_panic(vec[164] == true); + assert_or_panic(vec[165] == false); + assert_or_panic(vec[166] == false); + assert_or_panic(vec[167] == false); + assert_or_panic(vec[168] == false); + assert_or_panic(vec[169] == true); + assert_or_panic(vec[170] == false); + assert_or_panic(vec[171] == true); + assert_or_panic(vec[172] == false); + assert_or_panic(vec[173] == false); + assert_or_panic(vec[174] == false); + assert_or_panic(vec[175] == false); + assert_or_panic(vec[176] == true); + assert_or_panic(vec[177] == true); + assert_or_panic(vec[178] == true); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == true); + assert_or_panic(vec[181] == false); + assert_or_panic(vec[182] == true); + assert_or_panic(vec[183] == true); + assert_or_panic(vec[184] == false); + assert_or_panic(vec[185] == false); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == false); + assert_or_panic(vec[188] == false); + assert_or_panic(vec[189] == false); + assert_or_panic(vec[190] == false); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == true); + assert_or_panic(vec[193] == true); + assert_or_panic(vec[194] == true); + assert_or_panic(vec[195] == true); + assert_or_panic(vec[196] == true); + assert_or_panic(vec[197] == true); + assert_or_panic(vec[198] == false); + assert_or_panic(vec[199] == true); + assert_or_panic(vec[200] == false); + assert_or_panic(vec[201] == false); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == true); + assert_or_panic(vec[206] == true); + assert_or_panic(vec[207] == false); + assert_or_panic(vec[208] == false); + assert_or_panic(vec[209] == true); + assert_or_panic(vec[210] == true); + assert_or_panic(vec[211] == true); + assert_or_panic(vec[212] == false); + assert_or_panic(vec[213] == true); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == true); + assert_or_panic(vec[216] == true); + assert_or_panic(vec[217] == true); + assert_or_panic(vec[218] == false); + assert_or_panic(vec[219] == false); + assert_or_panic(vec[220] == false); + assert_or_panic(vec[221] == false); + assert_or_panic(vec[222] == false); + assert_or_panic(vec[223] == true); + assert_or_panic(vec[224] == true); + assert_or_panic(vec[225] == false); + assert_or_panic(vec[226] == true); + assert_or_panic(vec[227] == false); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == true); + assert_or_panic(vec[230] == false); + assert_or_panic(vec[231] == true); + assert_or_panic(vec[232] == false); + assert_or_panic(vec[233] == false); + assert_or_panic(vec[234] == false); + assert_or_panic(vec[235] == true); + assert_or_panic(vec[236] == false); + assert_or_panic(vec[237] == false); + assert_or_panic(vec[238] == false); + assert_or_panic(vec[239] == true); + assert_or_panic(vec[240] == true); + assert_or_panic(vec[241] == true); + assert_or_panic(vec[242] == true); + assert_or_panic(vec[243] == true); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == false); + assert_or_panic(vec[246] == false); + assert_or_panic(vec[247] == true); + assert_or_panic(vec[248] == false); + assert_or_panic(vec[249] == true); + assert_or_panic(vec[250] == true); + assert_or_panic(vec[251] == false); + assert_or_panic(vec[252] == true); + assert_or_panic(vec[253] == true); + assert_or_panic(vec[254] == true); + assert_or_panic(vec[255] == false); +} + +void c_vector_512_bool(Vector512Bool vec) { + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == true); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == true); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == false); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == true); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == false); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == true); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == true); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == false); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == true); + assert_or_panic(vec[47] == true); + assert_or_panic(vec[48] == false); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == false); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == true); + assert_or_panic(vec[59] == false); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == true); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == true); + assert_or_panic(vec[66] == true); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == true); + assert_or_panic(vec[69] == true); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == false); + assert_or_panic(vec[75] == true); + assert_or_panic(vec[76] == false); + assert_or_panic(vec[77] == true); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == false); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == true); + assert_or_panic(vec[82] == false); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == true); + assert_or_panic(vec[85] == false); + assert_or_panic(vec[86] == true); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == true); + assert_or_panic(vec[89] == false); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == true); + assert_or_panic(vec[92] == false); + assert_or_panic(vec[93] == true); + assert_or_panic(vec[94] == false); + assert_or_panic(vec[95] == true); + assert_or_panic(vec[96] == true); + assert_or_panic(vec[97] == false); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == false); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == true); + assert_or_panic(vec[102] == false); + assert_or_panic(vec[103] == true); + assert_or_panic(vec[104] == false); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == false); + assert_or_panic(vec[108] == false); + assert_or_panic(vec[109] == true); + assert_or_panic(vec[110] == false); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == true); + assert_or_panic(vec[116] == true); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == false); + assert_or_panic(vec[120] == false); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == false); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == true); + assert_or_panic(vec[126] == false); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == false); + assert_or_panic(vec[129] == true); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == false); + assert_or_panic(vec[132] == true); + assert_or_panic(vec[133] == false); + assert_or_panic(vec[134] == false); + assert_or_panic(vec[135] == false); + assert_or_panic(vec[136] == false); + assert_or_panic(vec[137] == true); + assert_or_panic(vec[138] == true); + assert_or_panic(vec[139] == false); + assert_or_panic(vec[140] == false); + assert_or_panic(vec[141] == false); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == true); + assert_or_panic(vec[144] == false); + assert_or_panic(vec[145] == false); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == true); + assert_or_panic(vec[148] == true); + assert_or_panic(vec[149] == true); + assert_or_panic(vec[150] == true); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == true); + assert_or_panic(vec[153] == false); + assert_or_panic(vec[154] == true); + assert_or_panic(vec[155] == false); + assert_or_panic(vec[156] == false); + assert_or_panic(vec[157] == true); + assert_or_panic(vec[158] == false); + assert_or_panic(vec[159] == true); + assert_or_panic(vec[160] == false); + assert_or_panic(vec[161] == true); + assert_or_panic(vec[162] == true); + assert_or_panic(vec[163] == true); + assert_or_panic(vec[164] == true); + assert_or_panic(vec[165] == true); + assert_or_panic(vec[166] == true); + assert_or_panic(vec[167] == true); + assert_or_panic(vec[168] == true); + assert_or_panic(vec[169] == false); + assert_or_panic(vec[170] == true); + assert_or_panic(vec[171] == true); + assert_or_panic(vec[172] == false); + assert_or_panic(vec[173] == true); + assert_or_panic(vec[174] == true); + assert_or_panic(vec[175] == false); + assert_or_panic(vec[176] == false); + assert_or_panic(vec[177] == false); + assert_or_panic(vec[178] == true); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == false); + assert_or_panic(vec[181] == true); + assert_or_panic(vec[182] == true); + assert_or_panic(vec[183] == true); + assert_or_panic(vec[184] == true); + assert_or_panic(vec[185] == true); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == true); + assert_or_panic(vec[188] == true); + assert_or_panic(vec[189] == true); + assert_or_panic(vec[190] == false); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == true); + assert_or_panic(vec[193] == false); + assert_or_panic(vec[194] == false); + assert_or_panic(vec[195] == true); + assert_or_panic(vec[196] == true); + assert_or_panic(vec[197] == false); + assert_or_panic(vec[198] == true); + assert_or_panic(vec[199] == true); + assert_or_panic(vec[200] == false); + assert_or_panic(vec[201] == true); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == true); + assert_or_panic(vec[206] == true); + assert_or_panic(vec[207] == true); + assert_or_panic(vec[208] == false); + assert_or_panic(vec[209] == true); + assert_or_panic(vec[210] == false); + assert_or_panic(vec[211] == true); + assert_or_panic(vec[212] == true); + assert_or_panic(vec[213] == false); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == false); + assert_or_panic(vec[216] == true); + assert_or_panic(vec[217] == false); + assert_or_panic(vec[218] == true); + assert_or_panic(vec[219] == false); + assert_or_panic(vec[220] == false); + assert_or_panic(vec[221] == true); + assert_or_panic(vec[222] == false); + assert_or_panic(vec[223] == false); + assert_or_panic(vec[224] == false); + assert_or_panic(vec[225] == true); + assert_or_panic(vec[226] == true); + assert_or_panic(vec[227] == false); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == false); + assert_or_panic(vec[230] == true); + assert_or_panic(vec[231] == false); + assert_or_panic(vec[232] == true); + assert_or_panic(vec[233] == false); + assert_or_panic(vec[234] == false); + assert_or_panic(vec[235] == false); + assert_or_panic(vec[236] == true); + assert_or_panic(vec[237] == true); + assert_or_panic(vec[238] == false); + assert_or_panic(vec[239] == false); + assert_or_panic(vec[240] == false); + assert_or_panic(vec[241] == false); + assert_or_panic(vec[242] == false); + assert_or_panic(vec[243] == true); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == false); + assert_or_panic(vec[246] == true); + assert_or_panic(vec[247] == false); + assert_or_panic(vec[248] == false); + assert_or_panic(vec[249] == true); + assert_or_panic(vec[250] == false); + assert_or_panic(vec[251] == false); + assert_or_panic(vec[252] == false); + assert_or_panic(vec[253] == true); + assert_or_panic(vec[254] == false); + assert_or_panic(vec[255] == false); + assert_or_panic(vec[256] == false); + assert_or_panic(vec[257] == false); + assert_or_panic(vec[258] == true); + assert_or_panic(vec[259] == true); + assert_or_panic(vec[260] == true); + assert_or_panic(vec[261] == true); + assert_or_panic(vec[262] == false); + assert_or_panic(vec[263] == true); + assert_or_panic(vec[264] == false); + assert_or_panic(vec[265] == false); + assert_or_panic(vec[266] == false); + assert_or_panic(vec[267] == true); + assert_or_panic(vec[268] == false); + assert_or_panic(vec[269] == false); + assert_or_panic(vec[270] == true); + assert_or_panic(vec[271] == true); + assert_or_panic(vec[272] == false); + assert_or_panic(vec[273] == false); + assert_or_panic(vec[274] == false); + assert_or_panic(vec[275] == false); + assert_or_panic(vec[276] == false); + assert_or_panic(vec[277] == true); + assert_or_panic(vec[278] == false); + assert_or_panic(vec[279] == true); + assert_or_panic(vec[280] == true); + assert_or_panic(vec[281] == true); + assert_or_panic(vec[282] == true); + assert_or_panic(vec[283] == true); + assert_or_panic(vec[284] == false); + assert_or_panic(vec[285] == false); + assert_or_panic(vec[286] == false); + assert_or_panic(vec[287] == false); + assert_or_panic(vec[288] == false); + assert_or_panic(vec[289] == false); + assert_or_panic(vec[290] == false); + assert_or_panic(vec[291] == false); + assert_or_panic(vec[292] == false); + assert_or_panic(vec[293] == true); + assert_or_panic(vec[294] == true); + assert_or_panic(vec[295] == true); + assert_or_panic(vec[296] == true); + assert_or_panic(vec[297] == true); + assert_or_panic(vec[298] == true); + assert_or_panic(vec[299] == false); + assert_or_panic(vec[300] == true); + assert_or_panic(vec[301] == false); + assert_or_panic(vec[302] == true); + assert_or_panic(vec[303] == true); + assert_or_panic(vec[304] == true); + assert_or_panic(vec[305] == false); + assert_or_panic(vec[306] == false); + assert_or_panic(vec[307] == true); + assert_or_panic(vec[308] == true); + assert_or_panic(vec[309] == true); + assert_or_panic(vec[310] == false); + assert_or_panic(vec[311] == true); + assert_or_panic(vec[312] == true); + assert_or_panic(vec[313] == true); + assert_or_panic(vec[314] == false); + assert_or_panic(vec[315] == true); + assert_or_panic(vec[316] == true); + assert_or_panic(vec[317] == true); + assert_or_panic(vec[318] == false); + assert_or_panic(vec[319] == true); + assert_or_panic(vec[320] == true); + assert_or_panic(vec[321] == false); + assert_or_panic(vec[322] == false); + assert_or_panic(vec[323] == true); + assert_or_panic(vec[324] == false); + assert_or_panic(vec[325] == false); + assert_or_panic(vec[326] == false); + assert_or_panic(vec[327] == false); + assert_or_panic(vec[328] == true); + assert_or_panic(vec[329] == false); + assert_or_panic(vec[330] == true); + assert_or_panic(vec[331] == true); + assert_or_panic(vec[332] == true); + assert_or_panic(vec[333] == true); + assert_or_panic(vec[334] == false); + assert_or_panic(vec[335] == false); + assert_or_panic(vec[336] == true); + assert_or_panic(vec[337] == false); + assert_or_panic(vec[338] == true); + assert_or_panic(vec[339] == false); + assert_or_panic(vec[340] == false); + assert_or_panic(vec[341] == false); + assert_or_panic(vec[342] == true); + assert_or_panic(vec[343] == false); + assert_or_panic(vec[344] == true); + assert_or_panic(vec[345] == false); + assert_or_panic(vec[346] == false); + assert_or_panic(vec[347] == true); + assert_or_panic(vec[348] == true); + assert_or_panic(vec[349] == true); + assert_or_panic(vec[350] == true); + assert_or_panic(vec[351] == false); + assert_or_panic(vec[352] == false); + assert_or_panic(vec[353] == false); + assert_or_panic(vec[354] == true); + assert_or_panic(vec[355] == true); + assert_or_panic(vec[356] == false); + assert_or_panic(vec[357] == true); + assert_or_panic(vec[358] == false); + assert_or_panic(vec[359] == false); + assert_or_panic(vec[360] == true); + assert_or_panic(vec[361] == false); + assert_or_panic(vec[362] == true); + assert_or_panic(vec[363] == false); + assert_or_panic(vec[364] == true); + assert_or_panic(vec[365] == true); + assert_or_panic(vec[366] == false); + assert_or_panic(vec[367] == false); + assert_or_panic(vec[368] == true); + assert_or_panic(vec[369] == true); + assert_or_panic(vec[370] == true); + assert_or_panic(vec[371] == true); + assert_or_panic(vec[372] == false); + assert_or_panic(vec[373] == false); + assert_or_panic(vec[374] == true); + assert_or_panic(vec[375] == false); + assert_or_panic(vec[376] == true); + assert_or_panic(vec[377] == true); + assert_or_panic(vec[378] == false); + assert_or_panic(vec[379] == true); + assert_or_panic(vec[380] == true); + assert_or_panic(vec[381] == false); + assert_or_panic(vec[382] == true); + assert_or_panic(vec[383] == true); + assert_or_panic(vec[384] == true); + assert_or_panic(vec[385] == false); + assert_or_panic(vec[386] == true); + assert_or_panic(vec[387] == true); + assert_or_panic(vec[388] == true); + assert_or_panic(vec[389] == false); + assert_or_panic(vec[390] == false); + assert_or_panic(vec[391] == true); + assert_or_panic(vec[392] == false); + assert_or_panic(vec[393] == true); + assert_or_panic(vec[394] == true); + assert_or_panic(vec[395] == true); + assert_or_panic(vec[396] == false); + assert_or_panic(vec[397] == false); + assert_or_panic(vec[398] == false); + assert_or_panic(vec[399] == false); + assert_or_panic(vec[400] == false); + assert_or_panic(vec[401] == true); + assert_or_panic(vec[402] == false); + assert_or_panic(vec[403] == false); + assert_or_panic(vec[404] == false); + assert_or_panic(vec[405] == false); + assert_or_panic(vec[406] == true); + assert_or_panic(vec[407] == false); + assert_or_panic(vec[408] == false); + assert_or_panic(vec[409] == true); + assert_or_panic(vec[410] == true); + assert_or_panic(vec[411] == false); + assert_or_panic(vec[412] == false); + assert_or_panic(vec[413] == false); + assert_or_panic(vec[414] == false); + assert_or_panic(vec[415] == true); + assert_or_panic(vec[416] == true); + assert_or_panic(vec[417] == true); + assert_or_panic(vec[418] == true); + assert_or_panic(vec[419] == true); + assert_or_panic(vec[420] == false); + assert_or_panic(vec[421] == false); + assert_or_panic(vec[422] == false); + assert_or_panic(vec[423] == true); + assert_or_panic(vec[424] == false); + assert_or_panic(vec[425] == false); + assert_or_panic(vec[426] == false); + assert_or_panic(vec[427] == false); + assert_or_panic(vec[428] == true); + assert_or_panic(vec[429] == false); + assert_or_panic(vec[430] == true); + assert_or_panic(vec[431] == false); + assert_or_panic(vec[432] == true); + assert_or_panic(vec[433] == true); + assert_or_panic(vec[434] == true); + assert_or_panic(vec[435] == true); + assert_or_panic(vec[436] == false); + assert_or_panic(vec[437] == false); + assert_or_panic(vec[438] == false); + assert_or_panic(vec[439] == false); + assert_or_panic(vec[440] == false); + assert_or_panic(vec[441] == true); + assert_or_panic(vec[442] == true); + assert_or_panic(vec[443] == true); + assert_or_panic(vec[444] == true); + assert_or_panic(vec[445] == true); + assert_or_panic(vec[446] == true); + assert_or_panic(vec[447] == true); + assert_or_panic(vec[448] == true); + assert_or_panic(vec[449] == true); + assert_or_panic(vec[450] == false); + assert_or_panic(vec[451] == false); + assert_or_panic(vec[452] == true); + assert_or_panic(vec[453] == false); + assert_or_panic(vec[454] == true); + assert_or_panic(vec[455] == false); + assert_or_panic(vec[456] == false); + assert_or_panic(vec[457] == true); + assert_or_panic(vec[458] == false); + assert_or_panic(vec[459] == false); + assert_or_panic(vec[460] == true); + assert_or_panic(vec[461] == true); + assert_or_panic(vec[462] == true); + assert_or_panic(vec[463] == true); + assert_or_panic(vec[464] == true); + assert_or_panic(vec[465] == true); + assert_or_panic(vec[466] == false); + assert_or_panic(vec[467] == true); + assert_or_panic(vec[468] == false); + assert_or_panic(vec[469] == false); + assert_or_panic(vec[470] == false); + assert_or_panic(vec[471] == true); + assert_or_panic(vec[472] == true); + assert_or_panic(vec[473] == false); + assert_or_panic(vec[474] == true); + assert_or_panic(vec[475] == true); + assert_or_panic(vec[476] == false); + assert_or_panic(vec[477] == false); + assert_or_panic(vec[478] == true); + assert_or_panic(vec[479] == true); + assert_or_panic(vec[480] == false); + assert_or_panic(vec[481] == false); + assert_or_panic(vec[482] == true); + assert_or_panic(vec[483] == true); + assert_or_panic(vec[484] == false); + assert_or_panic(vec[485] == true); + assert_or_panic(vec[486] == false); + assert_or_panic(vec[487] == true); + assert_or_panic(vec[488] == true); + assert_or_panic(vec[489] == true); + assert_or_panic(vec[490] == true); + assert_or_panic(vec[491] == true); + assert_or_panic(vec[492] == true); + assert_or_panic(vec[493] == true); + assert_or_panic(vec[494] == true); + assert_or_panic(vec[495] == true); + assert_or_panic(vec[496] == false); + assert_or_panic(vec[497] == true); + assert_or_panic(vec[498] == true); + assert_or_panic(vec[499] == true); + assert_or_panic(vec[500] == false); + assert_or_panic(vec[501] == false); + assert_or_panic(vec[502] == true); + assert_or_panic(vec[503] == false); + assert_or_panic(vec[504] == false); + assert_or_panic(vec[505] == false); + assert_or_panic(vec[506] == true); + assert_or_panic(vec[507] == true); + assert_or_panic(vec[508] == false); + assert_or_panic(vec[509] == true); + assert_or_panic(vec[510] == false); + assert_or_panic(vec[511] == true); +} + +#endif + +Vector2Bool c_ret_vector_2_bool(void) { + return (Vector2Bool){ + true, + false, + }; +} + +Vector4Bool c_ret_vector_4_bool(void) { + return (Vector4Bool){ + true, + false, + true, + false, + }; +} + +Vector8Bool c_ret_vector_8_bool(void) { + return (Vector8Bool){ + false, + true, + false, + false, + true, + false, + false, + true, + }; +} + +Vector16Bool c_ret_vector_16_bool(void) { + return (Vector16Bool){ + true, + true, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + }; +} + +Vector32Bool c_ret_vector_32_bool(void) { + return (Vector32Bool){ + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + }; +} + +Vector64Bool c_ret_vector_64_bool(void) { + return (Vector64Bool){ + false, + true, + false, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + }; +} + +Vector128Bool c_ret_vector_128_bool(void) { + return (Vector128Bool){ + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + }; +} + +Vector256Bool c_ret_vector_256_bool(void) { + return (Vector256Bool){ + true, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + }; +} + +Vector512Bool c_ret_vector_512_bool(void) { + return (Vector512Bool){ + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + }; +} + +void nat_vector_2_bool(Vector2Bool vec); +void nat_vector_4_bool(Vector4Bool vec); +void nat_vector_8_bool(Vector8Bool vec); +void nat_vector_16_bool(Vector16Bool vec); +void nat_vector_32_bool(Vector32Bool vec); +void nat_vector_64_bool(Vector64Bool vec); +void nat_vector_128_bool(Vector128Bool vec); +void nat_vector_256_bool(Vector256Bool vec); +void nat_vector_512_bool(Vector512Bool vec); + +Vector2Bool nat_ret_vector_2_bool(void); +Vector4Bool nat_ret_vector_4_bool(void); +Vector8Bool nat_ret_vector_8_bool(void); +Vector16Bool nat_ret_vector_16_bool(void); +Vector32Bool nat_ret_vector_32_bool(void); +Vector64Bool nat_ret_vector_64_bool(void); +Vector128Bool nat_ret_vector_128_bool(void); +Vector256Bool nat_ret_vector_256_bool(void); +Vector512Bool nat_ret_vector_512_bool(void); + +#endif + +typedef struct Vector3 { + float x; + float y; + float z; +} Vector3; + +typedef struct Vector5 { + float x; + float y; + float z; + float w; + float q; +} Vector5; + +typedef struct Rect { + uint32_t left; + uint32_t right; + uint32_t top; + uint32_t bottom; +} Rect; + +void nat_multiple_struct_ints(struct Rect, struct Rect); + +typedef struct FloatRect { + float left; + float right; + float top; + float bottom; +} FloatRect; + +void nat_multiple_struct_floats(struct FloatRect, struct FloatRect); + +void run_c_tests(void) { + nat_u8(0xff); + nat_u16(0xfffe); + nat_u32(0xfffffffd); + nat_u64(0xfffffffffffffffc); + +// #ifndef ZIG_NO_I128 +// { +// struct u128 s = {0xfffffffffffffffc}; +// nat_struct_u128(s); +// } +// #endif + +#ifndef ZIG_BUG_14908 + nat_s8(-1); + nat_s16(-2); +#endif + nat_s32(-3); + nat_s64(-4); + +// #ifndef ZIG_NO_I128 +// { +// struct i128 s = {-6}; +// nat_struct_i128(s); +// } +// #endif + + nat_five_integers(12, 34, 56, 78, 90); + + // nat_f32(12.34f); + // nat_f64(56.78); + // nat_longdouble(12.34l); + // nat_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f); + + nat_ptr((void *)0xdeadbeefL); + + nat_bool(true); + +#ifndef ZIG_NO_COMPLEX + // TODO: Resolve https://github.com/ziglang/zig/issues/8465 + //{ + // float complex a = 1.25f + I * 2.6f; + // float complex b = 11.3f - I * 1.5f; + // float complex z = nat_cmultf(a, b); + // assert_or_panic(creal(z) == 1.5f); + // assert_or_panic(cimag(z) == 13.5f); + //} + + // { + // double complex a = 1.25 + I * 2.6; + // double complex b = 11.3 - I * 1.5; + // double complex z = nat_cmultd(a, b); + // assert_or_panic(creal(z) == 1.5); + // assert_or_panic(cimag(z) == 13.5); + // } + + // { + // float a_r = 1.25f; + // float a_i = 2.6f; + // float b_r = 11.3f; + // float b_i = -1.5f; + // float complex z = nat_cmultf_comp(a_r, a_i, b_r, b_i); + // assert_or_panic(creal(z) == 1.5f); + // assert_or_panic(cimag(z) == 13.5f); + // } + + // { + // double a_r = 1.25; + // double a_i = 2.6; + // double b_r = 11.3; + // double b_i = -1.5; + // double complex z = nat_cmultd_comp(a_r, a_i, b_r, b_i); + // assert_or_panic(creal(z) == 1.5); + // assert_or_panic(cimag(z) == 13.5); + // } +#endif + +#if !defined(__mips__) && !defined(ZIG_PPC32) + { + struct Struct_u64_u64 s = nat_ret_struct_u64_u64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + nat_struct_u64_u64_0((struct Struct_u64_u64){ .a = 3, .b = 4 }); + nat_struct_u64_u64_1(0, (struct Struct_u64_u64){ .a = 5, .b = 6 }); + nat_struct_u64_u64_2(0, 1, (struct Struct_u64_u64){ .a = 7, .b = 8 }); + nat_struct_u64_u64_3(0, 1, 2, (struct Struct_u64_u64){ .a = 9, .b = 10 }); + nat_struct_u64_u64_4(0, 1, 2, 3, (struct Struct_u64_u64){ .a = 11, .b = 12 }); + nat_struct_u64_u64_5(0, 1, 2, 3, 4, (struct Struct_u64_u64){ .a = 13, .b = 14 }); + nat_struct_u64_u64_6(0, 1, 2, 3, 4, 5, (struct Struct_u64_u64){ .a = 15, .b = 16 }); + nat_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, (struct Struct_u64_u64){ .a = 17, .b = 18 }); + nat_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, (struct Struct_u64_u64){ .a = 19, .b = 20 }); + } +#endif + +#if !defined __mips__ && !defined ZIG_PPC32 + { + struct BigStruct s = {1, 2, 3, 4, 5}; + nat_big_struct(s); + } +#endif + +#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \ + !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64 + { + struct SmallStructInts s = {1, 2, 3, 4}; + nat_small_struct_ints(s); + } +#endif + +#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \ + !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64 + { + struct MedStructInts s = {1, 2, 3}; + nat_med_struct_ints(s); + } +#endif + +// #ifndef ZIG_NO_I128 +// { +// __int128 s = 0; +// s |= 1 << 0; +// s |= (__int128)2 << 64; +// nat_big_packed_struct(s); +// } +// #endif + + { + uint8_t s = 0; + s |= 0 << 0; + s |= 1 << 2; + s |= 2 << 4; + s |= 3 << 6; + nat_small_packed_struct(s); + } + +#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \ + !defined ZIG_PPC32 && !defined _ARCH_PPC64 + { + struct SplitStructInts s = {1234, 100, 1337}; + nat_split_struct_ints(s); + } +#endif + +// #if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64 +// { +// struct MedStructMixed s = {1234, 100.0f, 1337.0f}; +// nat_med_struct_mixed(s); +// } +// #endif +// +// #if !defined __i386__ && !defined __arm__ && !defined __mips__ && \ +// !defined ZIG_PPC32 && !defined _ARCH_PPC64 +// { +// struct SplitStructMixed s = {1234, 100, 1337.0f}; +// nat_split_struct_mixed(s); +// } +// #endif + +#if !defined __mips__ && !defined ZIG_PPC32 + { + struct BigStruct s = {30, 31, 32, 33, 34}; + struct BigStruct res = nat_big_struct_both(s); + assert_or_panic(res.a == 20); + assert_or_panic(res.b == 21); + assert_or_panic(res.c == 22); + assert_or_panic(res.d == 23); + assert_or_panic(res.e == 24); + } +#endif + +#if !defined ZIG_PPC32 && !defined _ARCH_PPC64 + { + struct Rect r1 = {1, 21, 16, 4}; + struct Rect r2 = {178, 189, 21, 15}; + nat_multiple_struct_ints(r1, r2); + } +#endif + +// #if !defined __mips__ && !defined ZIG_PPC32 +// { +// struct FloatRect r1 = {1, 21, 16, 4}; +// struct FloatRect r2 = {178, 189, 21, 15}; +// nat_multiple_struct_floats(r1, r2); +// } +// #endif + + { + assert_or_panic(nat_ret_bool() == 1); + + assert_or_panic(nat_ret_u8() == 0xff); + assert_or_panic(nat_ret_u16() == 0xffff); + assert_or_panic(nat_ret_u32() == 0xffffffff); + assert_or_panic(nat_ret_u64() == 0xffffffffffffffff); + + assert_or_panic(nat_ret_s8() == -1); + assert_or_panic(nat_ret_s16() == -1); + assert_or_panic(nat_ret_s32() == -1); + assert_or_panic(nat_ret_s64() == -1); + } + +#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) + { + nat_vector_2_bool((Vector2Bool){ + false, + true, + }); + + Vector2Bool vec = nat_ret_vector_2_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == false); + } + { + nat_vector_4_bool((Vector4Bool){ + false, + false, + false, + false, + }); + + Vector4Bool vec = nat_ret_vector_4_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + } + { + nat_vector_8_bool((Vector8Bool){ + true, + true, + false, + true, + false, + true, + true, + false, + }); + + Vector8Bool vec = nat_ret_vector_8_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == false); + } + { + nat_vector_16_bool((Vector16Bool){ + true, + false, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + }); + + Vector16Bool vec = nat_ret_vector_16_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + } + { + nat_vector_32_bool((Vector32Bool){ + false, + false, + false, + true, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + }); + + Vector32Bool vec = nat_ret_vector_32_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == false); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == true); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == false); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == true); + } + { + nat_vector_64_bool((Vector64Bool){ + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + }); + + Vector64Bool vec = nat_ret_vector_64_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == true); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == false); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == true); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == false); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == true); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == true); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == true); + assert_or_panic(vec[54] == false); + assert_or_panic(vec[55] == false); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == false); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == true); + assert_or_panic(vec[63] == false); + } + { + nat_vector_128_bool((Vector128Bool){ + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + }); + + Vector128Bool vec = nat_ret_vector_128_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == false); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == true); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == true); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == false); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == true); + assert_or_panic(vec[48] == false); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == false); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == false); + assert_or_panic(vec[56] == true); + assert_or_panic(vec[57] == false); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == true); + assert_or_panic(vec[62] == true); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == false); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == true); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == false); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == true); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == false); + assert_or_panic(vec[77] == true); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == true); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == false); + assert_or_panic(vec[85] == true); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == false); + assert_or_panic(vec[88] == true); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == true); + assert_or_panic(vec[92] == true); + assert_or_panic(vec[93] == false); + assert_or_panic(vec[94] == false); + assert_or_panic(vec[95] == true); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == false); + assert_or_panic(vec[98] == true); + assert_or_panic(vec[99] == true); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == true); + assert_or_panic(vec[102] == true); + assert_or_panic(vec[103] == true); + assert_or_panic(vec[104] == true); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == false); + assert_or_panic(vec[107] == true); + assert_or_panic(vec[108] == false); + assert_or_panic(vec[109] == false); + assert_or_panic(vec[110] == true); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == true); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == false); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == true); + assert_or_panic(vec[123] == false); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == false); + assert_or_panic(vec[127] == true); + } + { + nat_vector_256_bool((Vector256Bool){ + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + }); + + Vector256Bool vec = nat_ret_vector_256_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == false); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == false); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == false); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == false); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == false); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == true); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == true); + assert_or_panic(vec[51] == false); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == false); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == true); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == true); + assert_or_panic(vec[66] == false); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == true); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == false); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == false); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == false); + assert_or_panic(vec[77] == false); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == false); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == false); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == false); + assert_or_panic(vec[85] == false); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == false); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == false); + assert_or_panic(vec[92] == false); + assert_or_panic(vec[93] == true); + assert_or_panic(vec[94] == true); + assert_or_panic(vec[95] == false); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == true); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == false); + assert_or_panic(vec[100] == false); + assert_or_panic(vec[101] == false); + assert_or_panic(vec[102] == false); + assert_or_panic(vec[103] == false); + assert_or_panic(vec[104] == false); + assert_or_panic(vec[105] == true); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == false); + assert_or_panic(vec[108] == true); + assert_or_panic(vec[109] == false); + assert_or_panic(vec[110] == true); + assert_or_panic(vec[111] == true); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == true); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == false); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == true); + assert_or_panic(vec[129] == true); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == true); + assert_or_panic(vec[132] == false); + assert_or_panic(vec[133] == true); + assert_or_panic(vec[134] == true); + assert_or_panic(vec[135] == false); + assert_or_panic(vec[136] == false); + assert_or_panic(vec[137] == true); + assert_or_panic(vec[138] == true); + assert_or_panic(vec[139] == false); + assert_or_panic(vec[140] == true); + assert_or_panic(vec[141] == false); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == false); + assert_or_panic(vec[144] == true); + assert_or_panic(vec[145] == true); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == true); + assert_or_panic(vec[148] == false); + assert_or_panic(vec[149] == false); + assert_or_panic(vec[150] == false); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == false); + assert_or_panic(vec[153] == true); + assert_or_panic(vec[154] == false); + assert_or_panic(vec[155] == true); + assert_or_panic(vec[156] == true); + assert_or_panic(vec[157] == false); + assert_or_panic(vec[158] == true); + assert_or_panic(vec[159] == true); + assert_or_panic(vec[160] == true); + assert_or_panic(vec[161] == true); + assert_or_panic(vec[162] == true); + assert_or_panic(vec[163] == false); + assert_or_panic(vec[164] == false); + assert_or_panic(vec[165] == true); + assert_or_panic(vec[166] == false); + assert_or_panic(vec[167] == true); + assert_or_panic(vec[168] == true); + assert_or_panic(vec[169] == true); + assert_or_panic(vec[170] == true); + assert_or_panic(vec[171] == false); + assert_or_panic(vec[172] == true); + assert_or_panic(vec[173] == true); + assert_or_panic(vec[174] == true); + assert_or_panic(vec[175] == true); + assert_or_panic(vec[176] == true); + assert_or_panic(vec[177] == true); + assert_or_panic(vec[178] == true); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == true); + assert_or_panic(vec[181] == false); + assert_or_panic(vec[182] == false); + assert_or_panic(vec[183] == false); + assert_or_panic(vec[184] == true); + assert_or_panic(vec[185] == false); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == true); + assert_or_panic(vec[188] == false); + assert_or_panic(vec[189] == true); + assert_or_panic(vec[190] == false); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == false); + assert_or_panic(vec[193] == true); + assert_or_panic(vec[194] == false); + assert_or_panic(vec[195] == false); + assert_or_panic(vec[196] == true); + assert_or_panic(vec[197] == true); + assert_or_panic(vec[198] == true); + assert_or_panic(vec[199] == true); + assert_or_panic(vec[200] == true); + assert_or_panic(vec[201] == true); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == false); + assert_or_panic(vec[206] == false); + assert_or_panic(vec[207] == true); + assert_or_panic(vec[208] == true); + assert_or_panic(vec[209] == false); + assert_or_panic(vec[210] == false); + assert_or_panic(vec[211] == false); + assert_or_panic(vec[212] == true); + assert_or_panic(vec[213] == true); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == false); + assert_or_panic(vec[216] == false); + assert_or_panic(vec[217] == true); + assert_or_panic(vec[218] == true); + assert_or_panic(vec[219] == true); + assert_or_panic(vec[220] == true); + assert_or_panic(vec[221] == false); + assert_or_panic(vec[222] == true); + assert_or_panic(vec[223] == false); + assert_or_panic(vec[224] == true); + assert_or_panic(vec[225] == true); + assert_or_panic(vec[226] == true); + assert_or_panic(vec[227] == false); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == false); + assert_or_panic(vec[230] == false); + assert_or_panic(vec[231] == false); + assert_or_panic(vec[232] == true); + assert_or_panic(vec[233] == true); + assert_or_panic(vec[234] == false); + assert_or_panic(vec[235] == false); + assert_or_panic(vec[236] == false); + assert_or_panic(vec[237] == true); + assert_or_panic(vec[238] == true); + assert_or_panic(vec[239] == false); + assert_or_panic(vec[240] == true); + assert_or_panic(vec[241] == true); + assert_or_panic(vec[242] == true); + assert_or_panic(vec[243] == false); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == true); + assert_or_panic(vec[246] == false); + assert_or_panic(vec[247] == true); + assert_or_panic(vec[248] == false); + assert_or_panic(vec[249] == false); + assert_or_panic(vec[250] == true); + assert_or_panic(vec[251] == true); + assert_or_panic(vec[252] == false); + assert_or_panic(vec[253] == true); + assert_or_panic(vec[254] == false); + assert_or_panic(vec[255] == true); + } + { + nat_vector_512_bool((Vector512Bool){ + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + false, + false, + true, + false, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + true, + false, + false, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + true, + }); + + Vector512Bool vec = nat_ret_vector_512_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == false); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == false); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == true); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == true); + assert_or_panic(vec[34] == false); + assert_or_panic(vec[35] == false); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == false); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == true); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == true); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == false); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == false); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == true); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == true); + assert_or_panic(vec[67] == false); + assert_or_panic(vec[68] == false); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == true); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == true); + assert_or_panic(vec[77] == false); + assert_or_panic(vec[78] == true); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == true); + assert_or_panic(vec[81] == true); + assert_or_panic(vec[82] == true); + assert_or_panic(vec[83] == false); + assert_or_panic(vec[84] == true); + assert_or_panic(vec[85] == true); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == false); + assert_or_panic(vec[89] == false); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == false); + assert_or_panic(vec[92] == true); + assert_or_panic(vec[93] == false); + assert_or_panic(vec[94] == false); + assert_or_panic(vec[95] == false); + assert_or_panic(vec[96] == true); + assert_or_panic(vec[97] == true); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == true); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == false); + assert_or_panic(vec[102] == true); + assert_or_panic(vec[103] == false); + assert_or_panic(vec[104] == true); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == false); + assert_or_panic(vec[108] == false); + assert_or_panic(vec[109] == true); + assert_or_panic(vec[110] == false); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == true); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == true); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == true); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == true); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == false); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == true); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == false); + assert_or_panic(vec[129] == true); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == false); + assert_or_panic(vec[132] == true); + assert_or_panic(vec[133] == true); + assert_or_panic(vec[134] == false); + assert_or_panic(vec[135] == true); + assert_or_panic(vec[136] == true); + assert_or_panic(vec[137] == false); + assert_or_panic(vec[138] == false); + assert_or_panic(vec[139] == false); + assert_or_panic(vec[140] == true); + assert_or_panic(vec[141] == false); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == false); + assert_or_panic(vec[144] == false); + assert_or_panic(vec[145] == false); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == false); + assert_or_panic(vec[148] == true); + assert_or_panic(vec[149] == false); + assert_or_panic(vec[150] == false); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == false); + assert_or_panic(vec[153] == true); + assert_or_panic(vec[154] == true); + assert_or_panic(vec[155] == false); + assert_or_panic(vec[156] == true); + assert_or_panic(vec[157] == true); + assert_or_panic(vec[158] == false); + assert_or_panic(vec[159] == true); + assert_or_panic(vec[160] == true); + assert_or_panic(vec[161] == false); + assert_or_panic(vec[162] == false); + assert_or_panic(vec[163] == false); + assert_or_panic(vec[164] == true); + assert_or_panic(vec[165] == false); + assert_or_panic(vec[166] == true); + assert_or_panic(vec[167] == true); + assert_or_panic(vec[168] == true); + assert_or_panic(vec[169] == true); + assert_or_panic(vec[170] == false); + assert_or_panic(vec[171] == true); + assert_or_panic(vec[172] == false); + assert_or_panic(vec[173] == false); + assert_or_panic(vec[174] == true); + assert_or_panic(vec[175] == true); + assert_or_panic(vec[176] == true); + assert_or_panic(vec[177] == false); + assert_or_panic(vec[178] == false); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == true); + assert_or_panic(vec[181] == false); + assert_or_panic(vec[182] == false); + assert_or_panic(vec[183] == true); + assert_or_panic(vec[184] == true); + assert_or_panic(vec[185] == false); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == false); + assert_or_panic(vec[188] == true); + assert_or_panic(vec[189] == true); + assert_or_panic(vec[190] == true); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == true); + assert_or_panic(vec[193] == true); + assert_or_panic(vec[194] == true); + assert_or_panic(vec[195] == false); + assert_or_panic(vec[196] == false); + assert_or_panic(vec[197] == false); + assert_or_panic(vec[198] == false); + assert_or_panic(vec[199] == false); + assert_or_panic(vec[200] == true); + assert_or_panic(vec[201] == false); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == true); + assert_or_panic(vec[206] == false); + assert_or_panic(vec[207] == false); + assert_or_panic(vec[208] == false); + assert_or_panic(vec[209] == true); + assert_or_panic(vec[210] == true); + assert_or_panic(vec[211] == true); + assert_or_panic(vec[212] == false); + assert_or_panic(vec[213] == false); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == true); + assert_or_panic(vec[216] == true); + assert_or_panic(vec[217] == false); + assert_or_panic(vec[218] == false); + assert_or_panic(vec[219] == true); + assert_or_panic(vec[220] == false); + assert_or_panic(vec[221] == true); + assert_or_panic(vec[222] == true); + assert_or_panic(vec[223] == false); + assert_or_panic(vec[224] == true); + assert_or_panic(vec[225] == false); + assert_or_panic(vec[226] == false); + assert_or_panic(vec[227] == true); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == false); + assert_or_panic(vec[230] == true); + assert_or_panic(vec[231] == true); + assert_or_panic(vec[232] == false); + assert_or_panic(vec[233] == true); + assert_or_panic(vec[234] == true); + assert_or_panic(vec[235] == true); + assert_or_panic(vec[236] == true); + assert_or_panic(vec[237] == true); + assert_or_panic(vec[238] == false); + assert_or_panic(vec[239] == true); + assert_or_panic(vec[240] == false); + assert_or_panic(vec[241] == false); + assert_or_panic(vec[242] == true); + assert_or_panic(vec[243] == false); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == false); + assert_or_panic(vec[246] == true); + assert_or_panic(vec[247] == false); + assert_or_panic(vec[248] == true); + assert_or_panic(vec[249] == true); + assert_or_panic(vec[250] == true); + assert_or_panic(vec[251] == true); + assert_or_panic(vec[252] == true); + assert_or_panic(vec[253] == false); + assert_or_panic(vec[254] == false); + assert_or_panic(vec[255] == false); + assert_or_panic(vec[256] == false); + assert_or_panic(vec[257] == false); + assert_or_panic(vec[258] == false); + assert_or_panic(vec[259] == true); + assert_or_panic(vec[260] == true); + assert_or_panic(vec[261] == true); + assert_or_panic(vec[262] == true); + assert_or_panic(vec[263] == false); + assert_or_panic(vec[264] == false); + assert_or_panic(vec[265] == false); + assert_or_panic(vec[266] == true); + assert_or_panic(vec[267] == false); + assert_or_panic(vec[268] == true); + assert_or_panic(vec[269] == false); + assert_or_panic(vec[270] == true); + assert_or_panic(vec[271] == true); + assert_or_panic(vec[272] == true); + assert_or_panic(vec[273] == true); + assert_or_panic(vec[274] == true); + assert_or_panic(vec[275] == true); + assert_or_panic(vec[276] == false); + assert_or_panic(vec[277] == false); + assert_or_panic(vec[278] == true); + assert_or_panic(vec[279] == true); + assert_or_panic(vec[280] == false); + assert_or_panic(vec[281] == false); + assert_or_panic(vec[282] == false); + assert_or_panic(vec[283] == false); + assert_or_panic(vec[284] == true); + assert_or_panic(vec[285] == true); + assert_or_panic(vec[286] == true); + assert_or_panic(vec[287] == false); + assert_or_panic(vec[288] == false); + assert_or_panic(vec[289] == false); + assert_or_panic(vec[290] == true); + assert_or_panic(vec[291] == false); + assert_or_panic(vec[292] == true); + assert_or_panic(vec[293] == true); + assert_or_panic(vec[294] == false); + assert_or_panic(vec[295] == true); + assert_or_panic(vec[296] == true); + assert_or_panic(vec[297] == true); + assert_or_panic(vec[298] == false); + assert_or_panic(vec[299] == true); + assert_or_panic(vec[300] == true); + assert_or_panic(vec[301] == false); + assert_or_panic(vec[302] == false); + assert_or_panic(vec[303] == true); + assert_or_panic(vec[304] == false); + assert_or_panic(vec[305] == false); + assert_or_panic(vec[306] == true); + assert_or_panic(vec[307] == true); + assert_or_panic(vec[308] == true); + assert_or_panic(vec[309] == true); + assert_or_panic(vec[310] == false); + assert_or_panic(vec[311] == false); + assert_or_panic(vec[312] == false); + assert_or_panic(vec[313] == false); + assert_or_panic(vec[314] == false); + assert_or_panic(vec[315] == true); + assert_or_panic(vec[316] == false); + assert_or_panic(vec[317] == false); + assert_or_panic(vec[318] == true); + assert_or_panic(vec[319] == false); + assert_or_panic(vec[320] == false); + assert_or_panic(vec[321] == true); + assert_or_panic(vec[322] == true); + assert_or_panic(vec[323] == true); + assert_or_panic(vec[324] == true); + assert_or_panic(vec[325] == false); + assert_or_panic(vec[326] == false); + assert_or_panic(vec[327] == false); + assert_or_panic(vec[328] == true); + assert_or_panic(vec[329] == true); + assert_or_panic(vec[330] == false); + assert_or_panic(vec[331] == true); + assert_or_panic(vec[332] == true); + assert_or_panic(vec[333] == false); + assert_or_panic(vec[334] == false); + assert_or_panic(vec[335] == true); + assert_or_panic(vec[336] == true); + assert_or_panic(vec[337] == false); + assert_or_panic(vec[338] == true); + assert_or_panic(vec[339] == true); + assert_or_panic(vec[340] == true); + assert_or_panic(vec[341] == false); + assert_or_panic(vec[342] == false); + assert_or_panic(vec[343] == false); + assert_or_panic(vec[344] == true); + assert_or_panic(vec[345] == true); + assert_or_panic(vec[346] == false); + assert_or_panic(vec[347] == true); + assert_or_panic(vec[348] == false); + assert_or_panic(vec[349] == true); + assert_or_panic(vec[350] == false); + assert_or_panic(vec[351] == false); + assert_or_panic(vec[352] == true); + assert_or_panic(vec[353] == false); + assert_or_panic(vec[354] == true); + assert_or_panic(vec[355] == false); + assert_or_panic(vec[356] == false); + assert_or_panic(vec[357] == false); + assert_or_panic(vec[358] == false); + assert_or_panic(vec[359] == false); + assert_or_panic(vec[360] == true); + assert_or_panic(vec[361] == true); + assert_or_panic(vec[362] == false); + assert_or_panic(vec[363] == false); + assert_or_panic(vec[364] == false); + assert_or_panic(vec[365] == false); + assert_or_panic(vec[366] == true); + assert_or_panic(vec[367] == false); + assert_or_panic(vec[368] == true); + assert_or_panic(vec[369] == false); + assert_or_panic(vec[370] == true); + assert_or_panic(vec[371] == true); + assert_or_panic(vec[372] == false); + assert_or_panic(vec[373] == true); + assert_or_panic(vec[374] == true); + assert_or_panic(vec[375] == true); + assert_or_panic(vec[376] == true); + assert_or_panic(vec[377] == true); + assert_or_panic(vec[378] == false); + assert_or_panic(vec[379] == true); + assert_or_panic(vec[380] == false); + assert_or_panic(vec[381] == true); + assert_or_panic(vec[382] == true); + assert_or_panic(vec[383] == true); + assert_or_panic(vec[384] == true); + assert_or_panic(vec[385] == true); + assert_or_panic(vec[386] == false); + assert_or_panic(vec[387] == true); + assert_or_panic(vec[388] == true); + assert_or_panic(vec[389] == false); + assert_or_panic(vec[390] == true); + assert_or_panic(vec[391] == false); + assert_or_panic(vec[392] == true); + assert_or_panic(vec[393] == false); + assert_or_panic(vec[394] == true); + assert_or_panic(vec[395] == false); + assert_or_panic(vec[396] == true); + assert_or_panic(vec[397] == false); + assert_or_panic(vec[398] == false); + assert_or_panic(vec[399] == true); + assert_or_panic(vec[400] == true); + assert_or_panic(vec[401] == true); + assert_or_panic(vec[402] == true); + assert_or_panic(vec[403] == false); + assert_or_panic(vec[404] == false); + assert_or_panic(vec[405] == true); + assert_or_panic(vec[406] == false); + assert_or_panic(vec[407] == false); + assert_or_panic(vec[408] == false); + assert_or_panic(vec[409] == true); + assert_or_panic(vec[410] == false); + assert_or_panic(vec[411] == true); + assert_or_panic(vec[412] == true); + assert_or_panic(vec[413] == false); + assert_or_panic(vec[414] == true); + assert_or_panic(vec[415] == true); + assert_or_panic(vec[416] == false); + assert_or_panic(vec[417] == true); + assert_or_panic(vec[418] == true); + assert_or_panic(vec[419] == false); + assert_or_panic(vec[420] == false); + assert_or_panic(vec[421] == true); + assert_or_panic(vec[422] == false); + assert_or_panic(vec[423] == false); + assert_or_panic(vec[424] == true); + assert_or_panic(vec[425] == false); + assert_or_panic(vec[426] == true); + assert_or_panic(vec[427] == false); + assert_or_panic(vec[428] == false); + assert_or_panic(vec[429] == true); + assert_or_panic(vec[430] == false); + assert_or_panic(vec[431] == true); + assert_or_panic(vec[432] == true); + assert_or_panic(vec[433] == false); + assert_or_panic(vec[434] == true); + assert_or_panic(vec[435] == false); + assert_or_panic(vec[436] == true); + assert_or_panic(vec[437] == false); + assert_or_panic(vec[438] == true); + assert_or_panic(vec[439] == false); + assert_or_panic(vec[440] == false); + assert_or_panic(vec[441] == true); + assert_or_panic(vec[442] == true); + assert_or_panic(vec[443] == false); + assert_or_panic(vec[444] == true); + assert_or_panic(vec[445] == true); + assert_or_panic(vec[446] == false); + assert_or_panic(vec[447] == true); + assert_or_panic(vec[448] == true); + assert_or_panic(vec[449] == false); + assert_or_panic(vec[450] == false); + assert_or_panic(vec[451] == false); + assert_or_panic(vec[452] == false); + assert_or_panic(vec[453] == false); + assert_or_panic(vec[454] == true); + assert_or_panic(vec[455] == false); + assert_or_panic(vec[456] == false); + assert_or_panic(vec[457] == true); + assert_or_panic(vec[458] == false); + assert_or_panic(vec[459] == true); + assert_or_panic(vec[460] == false); + assert_or_panic(vec[461] == false); + assert_or_panic(vec[462] == false); + assert_or_panic(vec[463] == true); + assert_or_panic(vec[464] == false); + assert_or_panic(vec[465] == true); + assert_or_panic(vec[466] == false); + assert_or_panic(vec[467] == false); + assert_or_panic(vec[468] == false); + assert_or_panic(vec[469] == false); + assert_or_panic(vec[470] == true); + assert_or_panic(vec[471] == true); + assert_or_panic(vec[472] == false); + assert_or_panic(vec[473] == true); + assert_or_panic(vec[474] == true); + assert_or_panic(vec[475] == false); + assert_or_panic(vec[476] == false); + assert_or_panic(vec[477] == true); + assert_or_panic(vec[478] == true); + assert_or_panic(vec[479] == true); + assert_or_panic(vec[480] == false); + assert_or_panic(vec[481] == false); + assert_or_panic(vec[482] == true); + assert_or_panic(vec[483] == false); + assert_or_panic(vec[484] == false); + assert_or_panic(vec[485] == false); + assert_or_panic(vec[486] == true); + assert_or_panic(vec[487] == true); + assert_or_panic(vec[488] == false); + assert_or_panic(vec[489] == false); + assert_or_panic(vec[490] == false); + assert_or_panic(vec[491] == false); + assert_or_panic(vec[492] == false); + assert_or_panic(vec[493] == true); + assert_or_panic(vec[494] == true); + assert_or_panic(vec[495] == true); + assert_or_panic(vec[496] == true); + assert_or_panic(vec[497] == false); + assert_or_panic(vec[498] == false); + assert_or_panic(vec[499] == false); + assert_or_panic(vec[500] == true); + assert_or_panic(vec[501] == false); + assert_or_panic(vec[502] == true); + assert_or_panic(vec[503] == true); + assert_or_panic(vec[504] == true); + assert_or_panic(vec[505] == true); + assert_or_panic(vec[506] == false); + assert_or_panic(vec[507] == false); + assert_or_panic(vec[508] == true); + assert_or_panic(vec[509] == true); + assert_or_panic(vec[510] == false); + assert_or_panic(vec[511] == false); + } +#endif +} + +void c_u8(uint8_t x) { + assert_or_panic(x == 0xff); +} + +void c_u16(uint16_t x) { + assert_or_panic(x == 0xfffe); +} + +void c_u32(uint32_t x) { + assert_or_panic(x == 0xfffffffd); +} + +void c_u64(uint64_t x) { + assert_or_panic(x == 0xfffffffffffffffcULL); +} + +// #ifndef ZIG_NO_I128 +// void c_struct_u128(struct u128 x) { +// assert_or_panic(x.value == 0xfffffffffffffffcULL); +// } +// #endif + +void c_s8(int8_t x) { + assert_or_panic(x == -1); +} + +void c_s16(int16_t x) { + assert_or_panic(x == -2); +} + +void c_s32(int32_t x) { + assert_or_panic(x == -3); +} + +void c_s64(int64_t x) { + assert_or_panic(x == -4); +} + +// #ifndef ZIG_NO_I128 +// void c_struct_i128(struct i128 x) { +// assert_or_panic(x.value == -6); +// } +// #endif + +// void c_f32(float x) { +// assert_or_panic(x == 12.34f); +// } + +// void c_f64(double x) { +// assert_or_panic(x == 56.78); +// } +// +// void c_long_double(long double x) { +// assert_or_panic(x == 12.34l); +// } + +void c_ptr(void *x) { + assert_or_panic(x == (void *)0xdeadbeefL); +} + +void c_bool(bool x) { + assert_or_panic(x); +} + +void c_five_integers(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e) { + assert_or_panic(a == 12); + assert_or_panic(b == 34); + assert_or_panic(c == 56); + assert_or_panic(d == 78); + assert_or_panic(e == 90); +} + +// void c_five_floats(float a, float b, float c, float d, float e) { +// assert_or_panic(a == 1.0); +// assert_or_panic(b == 2.0); +// assert_or_panic(c == 3.0); +// assert_or_panic(d == 4.0); +// assert_or_panic(e == 5.0); +// } +// +// float complex c_cmultf_comp(float a_r, float a_i, float b_r, float b_i) { +// assert_or_panic(a_r == 1.25f); +// assert_or_panic(a_i == 2.6f); +// assert_or_panic(b_r == 11.3f); +// assert_or_panic(b_i == -1.5f); +// +// return 1.5f + I * 13.5f; +// } +// +// double complex c_cmultd_comp(double a_r, double a_i, double b_r, double b_i) { +// assert_or_panic(a_r == 1.25); +// assert_or_panic(a_i == 2.6); +// assert_or_panic(b_r == 11.3); +// assert_or_panic(b_i == -1.5); +// +// return 1.5 + I * 13.5; +// } +// +// float complex c_cmultf(float complex a, float complex b) { +// assert_or_panic(creal(a) == 1.25f); +// assert_or_panic(cimag(a) == 2.6f); +// assert_or_panic(creal(b) == 11.3f); +// assert_or_panic(cimag(b) == -1.5f); +// +// return 1.5f + I * 13.5f; +// } +// +// double complex c_cmultd(double complex a, double complex b) { +// assert_or_panic(creal(a) == 1.25); +// assert_or_panic(cimag(a) == 2.6); +// assert_or_panic(creal(b) == 11.3); +// assert_or_panic(cimag(b) == -1.5); +// +// return 1.5 + I * 13.5; +// } + +void c_big_struct(struct BigStruct x) { + assert_or_panic(x.a == 1); + assert_or_panic(x.b == 2); + assert_or_panic(x.c == 3); + assert_or_panic(x.d == 4); + assert_or_panic(x.e == 5); +} + +void c_big_union(union BigUnion x) { + assert_or_panic(x.a.a == 1); + assert_or_panic(x.a.b == 2); + assert_or_panic(x.a.c == 3); + assert_or_panic(x.a.d == 4); +} + +void c_small_struct_ints(struct SmallStructInts x) { + assert_or_panic(x.a == 1); + assert_or_panic(x.b == 2); + assert_or_panic(x.c == 3); + assert_or_panic(x.d == 4); + + struct SmallStructInts y = nat_ret_small_struct_ints(); + + assert_or_panic(y.a == 1); + assert_or_panic(y.b == 2); + assert_or_panic(y.c == 3); + assert_or_panic(y.d == 4); +} + +struct SmallStructInts c_ret_small_struct_ints() { + struct SmallStructInts s = { + .a = 1, + .b = 2, + .c = 3, + .d = 4, + }; + return s; +} + +void c_med_struct_ints(struct MedStructInts s) { + assert_or_panic(s.x == 1); + assert_or_panic(s.y == 2); + assert_or_panic(s.z == 3); + + struct MedStructInts s2 = nat_ret_med_struct_ints(); + + assert_or_panic(s2.x == 1); + assert_or_panic(s2.y == 2); + assert_or_panic(s2.z == 3); +} + +struct MedStructInts c_ret_med_struct_ints() { + struct MedStructInts s = { + .x = 1, + .y = 2, + .z = 3, + }; + return s; +} + +// void c_med_struct_mixed(struct MedStructMixed x) { +// assert_or_panic(x.a == 1234); +// assert_or_panic(x.b == 100.0f); +// assert_or_panic(x.c == 1337.0f); +// +// struct MedStructMixed y = nat_ret_med_struct_mixed(); +// +// assert_or_panic(y.a == 1234); +// assert_or_panic(y.b == 100.0f); +// assert_or_panic(y.c == 1337.0f); +// } + +struct MedStructMixed c_ret_med_struct_mixed() { + struct MedStructMixed s = { + .a = 1234, + .b = 100.0, + .c = 1337.0, + }; + return s; +} + +void c_split_struct_ints(struct SplitStructInts x) { + assert_or_panic(x.a == 1234); + assert_or_panic(x.b == 100); + assert_or_panic(x.c == 1337); +} + +// void c_split_struct_mixed(struct SplitStructMixed x) { +// assert_or_panic(x.a == 1234); +// assert_or_panic(x.b == 100); +// assert_or_panic(x.c == 1337.0f); +// struct SplitStructMixed y = nat_ret_split_struct_mixed(); +// +// assert_or_panic(y.a == 1234); +// assert_or_panic(y.b == 100); +// assert_or_panic(y.c == 1337.0f); +// } + +uint8_t c_ret_small_packed_struct() { + uint8_t s = 0; + s |= 0 << 0; + s |= 1 << 2; + s |= 2 << 4; + s |= 3 << 6; + return s; +} + +void c_small_packed_struct(uint8_t x) { + assert_or_panic(((x >> 0) & 0x3) == 0); + assert_or_panic(((x >> 2) & 0x3) == 1); + assert_or_panic(((x >> 4) & 0x3) == 2); + assert_or_panic(((x >> 6) & 0x3) == 3); +} + +// #ifndef ZIG_NO_I128 +// __int128 c_ret_big_packed_struct() { +// __int128 s = 0; +// s |= 1 << 0; +// s |= (__int128)2 << 64; +// return s; +// } + +// void c_big_packed_struct(__int128 x) { +// assert_or_panic(((x >> 0) & 0xFFFFFFFFFFFFFFFF) == 1); +// assert_or_panic(((x >> 64) & 0xFFFFFFFFFFFFFFFF) == 2); +// } +// #endif + +struct SplitStructMixed c_ret_split_struct_mixed() { + struct SplitStructMixed s = { + .a = 1234, + .b = 100, + .c = 1337.0f, + }; + return s; +} + +struct BigStruct c_big_struct_both(struct BigStruct x) { + assert_or_panic(x.a == 1); + assert_or_panic(x.b == 2); + assert_or_panic(x.c == 3); + assert_or_panic(x.d == 4); + assert_or_panic(x.e == 5); + struct BigStruct y = {10, 11, 12, 13, 14}; + return y; +} + +void c_small_struct_floats(Vector3 vec) { + assert_or_panic(vec.x == 3.0); + assert_or_panic(vec.y == 6.0); + assert_or_panic(vec.z == 12.0); +} + +// void c_small_struct_floats_extra(Vector3 vec, const char *str) { +// assert_or_panic(vec.x == 3.0); +// assert_or_panic(vec.y == 6.0); +// assert_or_panic(vec.z == 12.0); +// assert_or_panic(!strcmp(str, "hello")); +// } + +void c_big_struct_floats(Vector5 vec) { + assert_or_panic(vec.x == 76.0); + assert_or_panic(vec.y == -1.0); + assert_or_panic(vec.z == -12.0); + assert_or_panic(vec.w == 69); + assert_or_panic(vec.q == 55); +} + +void c_multiple_struct_ints(Rect x, Rect y) { + assert_or_panic(x.left == 1); + assert_or_panic(x.right == 21); + assert_or_panic(x.top == 16); + assert_or_panic(x.bottom == 4); + assert_or_panic(y.left == 178); + assert_or_panic(y.right == 189); + assert_or_panic(y.top == 21); + assert_or_panic(y.bottom == 15); +} + +void c_multiple_struct_floats(FloatRect x, FloatRect y) { + assert_or_panic(x.left == 1); + assert_or_panic(x.right == 21); + assert_or_panic(x.top == 16); + assert_or_panic(x.bottom == 4); + assert_or_panic(y.left == 178); + assert_or_panic(y.right == 189); + assert_or_panic(y.top == 21); + assert_or_panic(y.bottom == 15); +} + +bool c_ret_bool() { + return 1; +} +uint8_t c_ret_u8() { + return 0xff; +} +uint16_t c_ret_u16() { + return 0xffff; +} +uint32_t c_ret_u32() { + return 0xffffffff; +} +uint64_t c_ret_u64() { + return 0xffffffffffffffff; +} +int8_t c_ret_s8() { + return -1; +} +int16_t c_ret_s16() { + return -1; +} +int32_t c_ret_s32() { + return -1; +} +int64_t c_ret_s64() { + return -1; +} + +typedef struct { + uint32_t a; + uint8_t padding[4]; + uint64_t b; +} StructWithArray; + +void c_struct_with_array(StructWithArray x) { + assert_or_panic(x.a == 1); + assert_or_panic(x.b == 2); +} + +StructWithArray c_ret_struct_with_array() { + return (StructWithArray){4, {}, 155}; +} + +typedef struct { + struct Point { + double x; + double y; + } origin; + struct Size { + double width; + double height; + } size; +} FloatArrayStruct; + +void c_float_array_struct(FloatArrayStruct x) { + assert_or_panic(x.origin.x == 5); + assert_or_panic(x.origin.y == 6); + assert_or_panic(x.size.width == 7); + assert_or_panic(x.size.height == 8); +} + +FloatArrayStruct c_ret_float_array_struct() { + FloatArrayStruct x; + x.origin.x = 1; + x.origin.y = 2; + x.size.width = 3; + x.size.height = 4; + return x; +} + +typedef uint32_t SmallVec __attribute__((vector_size(2 * sizeof(uint32_t)))); + +void c_small_vec(SmallVec vec) { + assert_or_panic(vec[0] == 1); + assert_or_panic(vec[1] == 2); +} + +SmallVec c_ret_small_vec(void) { + return (SmallVec){3, 4}; +} + +typedef size_t MediumVec __attribute__((vector_size(4 * sizeof(size_t)))); + +void c_medium_vec(MediumVec vec) { + assert_or_panic(vec[0] == 1); + assert_or_panic(vec[1] == 2); + assert_or_panic(vec[2] == 3); + assert_or_panic(vec[3] == 4); +} + +MediumVec c_ret_medium_vec(void) { + return (MediumVec){5, 6, 7, 8}; +} + +typedef size_t BigVec __attribute__((vector_size(8 * sizeof(size_t)))); + +void c_big_vec(BigVec vec) { + assert_or_panic(vec[0] == 1); + assert_or_panic(vec[1] == 2); + assert_or_panic(vec[2] == 3); + assert_or_panic(vec[3] == 4); + assert_or_panic(vec[4] == 5); + assert_or_panic(vec[5] == 6); + assert_or_panic(vec[6] == 7); + assert_or_panic(vec[7] == 8); +} + +BigVec c_ret_big_vec(void) { + return (BigVec){9, 10, 11, 12, 13, 14, 15, 16}; +} + +typedef struct { + float x, y; +} Vector2; + +void c_ptr_size_float_struct(Vector2 vec) { + assert_or_panic(vec.x == 1); + assert_or_panic(vec.y == 2); +} +Vector2 c_ret_ptr_size_float_struct(void) { + return (Vector2){3, 4}; +} + +/// Tests for Double + Char struct +// struct DC { double v1; char v2; }; + +// int c_assert_DC(struct DC lv){ +// if (lv.v1 != -0.25) return 1; +// if (lv.v2 != 15) return 2; +// return 0; +// } +// struct DC c_ret_DC(){ +// struct DC lv = { .v1 = -0.25, .v2 = 15 }; +// return lv; +// } +// int nat_assert_DC(struct DC); +// int c_send_DC(){ +// return nat_assert_DC(c_ret_DC()); +// } +// struct DC nat_ret_DC(); +// int c_assert_ret_DC(){ +// return c_assert_DC(nat_ret_DC()); +// } + +/// Tests for Char + Float + Float struct +struct CFF { char v1; float v2; float v3; }; + + +int c_assert_CFF(struct CFF lv){ + if (lv.v1 != 39) return 1; + if (lv.v2 != 0.875) return 2; + if (lv.v3 != 1.0) return 3; + return 0; +} +struct CFF c_ret_CFF(){ + struct CFF lv = { .v1 = 39, .v2 = 0.875, .v3 = 1.0 }; + return lv; +} +// int nat_assert_CFF(struct CFF); +// int c_send_CFF(){ +// return nat_assert_CFF(c_ret_CFF()); +// } +// struct CFF nat_ret_CFF(); +// int c_assert_ret_CFF(){ +// return c_assert_CFF(nat_ret_CFF()); +// } + +// struct PD { void* v1; double v2; }; +// +// int c_assert_PD(struct PD lv){ +// if (lv.v1 != 0) return 1; +// if (lv.v2 != 0.5) return 2; +// return 0; +// } +// struct PD c_ret_PD(){ +// struct PD lv = { .v1 = 0, .v2 = 0.5 }; +// return lv; +// } +// int nat_assert_PD(struct PD); +// int c_send_PD(){ +// return nat_assert_PD(c_ret_PD()); +// } +// struct PD nat_ret_PD(); +// int c_assert_ret_PD(){ +// return c_assert_PD(nat_ret_PD()); +// } + +struct ByRef { + int val; + int arr[15]; +}; +struct ByRef c_modify_by_ref_param(struct ByRef in) { + in.val = 42; + return in; +} + +struct ByVal { + struct { + unsigned long x; + unsigned long y; + unsigned long z; + } origin; + struct { + unsigned long width; + unsigned long height; + unsigned long depth; + } size; +}; + +void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *d, unsigned long e) { + assert_or_panic((intptr_t)a == 1); + assert_or_panic((intptr_t)b == 2); + + assert_or_panic(in.origin.x == 9); + assert_or_panic(in.origin.y == 10); + assert_or_panic(in.origin.z == 11); + assert_or_panic(in.size.width == 12); + assert_or_panic(in.size.height == 13); + assert_or_panic(in.size.depth == 14); + + assert_or_panic(c == 3); + assert_or_panic((intptr_t)d == 4); + assert_or_panic(e == 5); +} + +#ifndef ZIG_NO_RAW_F16 +__fp16 c_f16(__fp16 a) { + assert_or_panic(a == 12); + return 34; +} +#endif + +typedef struct { + __fp16 a; +} f16_struct; +// f16_struct c_f16_struct(f16_struct a) { +// assert_or_panic(a.a == 12); +// return (f16_struct){34}; +// } + +// #if defined __x86_64__ || defined __i386__ +// typedef long double f80; +// f80 c_f80(f80 a) { +// assert_or_panic((double)a == 12.34); +// return 56.78; +// } +// typedef struct { +// f80 a; +// } f80_struct; +// f80_struct c_f80_struct(f80_struct a) { +// assert_or_panic((double)a.a == 12.34); +// return (f80_struct){56.78}; +// } +// typedef struct { +// f80 a; +// int b; +// } f80_extra_struct; +// f80_extra_struct c_f80_extra_struct(f80_extra_struct a) { +// assert_or_panic((double)a.a == 12.34); +// assert_or_panic(a.b == 42); +// return (f80_extra_struct){56.78, 24}; +// } +// #endif + +// #ifndef ZIG_NO_F128 +// __float128 c_f128(__float128 a) { +// assert_or_panic((double)a == 12.34); +// return 56.78; +// } +// typedef struct { +// __float128 a; +// } f128_struct; +// f128_struct c_f128_struct(f128_struct a) { +// assert_or_panic((double)a.a == 12.34); +// return (f128_struct){56.78}; +// } +// #endif + +void __attribute__((stdcall)) stdcall_scalars(char a, short b, int c, float d, double e) { + assert_or_panic(a == 1); + assert_or_panic(b == 2); + assert_or_panic(c == 3); + assert_or_panic(d == 4.0); + assert_or_panic(e == 5.0); +} + +typedef struct { + short x; + short y; +} Coord2; + +Coord2 __attribute__((stdcall)) stdcall_coord2(Coord2 a, Coord2 b, Coord2 c) { + assert_or_panic(a.x == 0x1111); + assert_or_panic(a.y == 0x2222); + assert_or_panic(b.x == 0x3333); + assert_or_panic(b.y == 0x4444); + assert_or_panic(c.x == 0x5555); + assert_or_panic(c.y == 0x6666); + return (Coord2){123, 456}; +} + +void __attribute__((stdcall)) stdcall_big_union(union BigUnion x) { + assert_or_panic(x.a.a == 1); + assert_or_panic(x.a.b == 2); + assert_or_panic(x.a.c == 3); + assert_or_panic(x.a.d == 4); +} + +#ifdef __x86_64__ +struct ByRef __attribute__((ms_abi)) c_explict_win64(struct ByRef in) { + in.val = 42; + return in; +} + +struct ByRef __attribute__((sysv_abi)) c_explict_sys_v(struct ByRef in) { + in.val = 42; + return in; +} +#endif + + +// struct byval_tail_callsite_attr_Point { +// double x; +// double y; +// } Point; +// struct byval_tail_callsite_attr_Size { +// double width; +// double height; +// } Size; +// struct byval_tail_callsite_attr_Rect { +// struct byval_tail_callsite_attr_Point origin; +// struct byval_tail_callsite_attr_Size size; +// }; +// double c_byval_tail_callsite_attr(struct byval_tail_callsite_attr_Rect in) { +// return in.size.width; +// } diff --git a/test/build/c-abi/foo.c b/test/build/c-abi/foo.c deleted file mode 100644 index 6c420c2..0000000 --- a/test/build/c-abi/foo.c +++ /dev/null @@ -1,5 +0,0 @@ -typedef unsigned u32; -u32 foo(u32 arg) -{ - return arg; -} diff --git a/test/build/c-abi/main.nat b/test/build/c-abi/main.nat index 2d7b711..e690672 100644 --- a/test/build/c-abi/main.nat +++ b/test/build/c-abi/main.nat @@ -1,7 +1,490 @@ const std = #import("std"); const expect = std.testing.expect; -const foo :: extern = fn(arg: u32) u32; +const run_c_tests :: extern = fn cc(.c) () void; +const has_i128 = false; + const main = fn () *!void { - const arg = 0xabcdef; - try expect(foo(arg) == arg); + run_c_tests(); + + c_u8(0xff); + c_u16(0xfffe); + c_u32(0xfffffffd); + c_u64(0xfffffffffffffffc); + + if (has_i128) { + c_struct_u128(.{ .value = 0xfffffffffffffffc, }); + } + + c_s8(-1); + c_s16(-2); + c_s32(-3); + c_s64(-4); + + if (has_i128) { + c_struct_i128(.{ .value = -6, }); + } + + c_bool(true); + + c_five_integers(12, 34, 56, 78, 90); + + const s = c_ret_struct_u64_u64(); + try expect(s.a == 21); + try expect(s.b == 22); + c_struct_u64_u64_0(.{ .a = 23, .b = 24, }); + c_struct_u64_u64_1(0, .{ .a = 25, .b = 26, }); + c_struct_u64_u64_2(0, 1, .{ .a = 27, .b = 28, }); + c_struct_u64_u64_3(0, 1, 2, .{ .a = 29, .b = 30, }); + c_struct_u64_u64_4(0, 1, 2, 3, .{ .a = 31, .b = 32, }); + c_struct_u64_u64_5(0, 1, 2, 3, 4, .{ .a = 33, .b = 34, }); + c_struct_u64_u64_6(0, 1, 2, 3, 4, 5, .{ .a = 35, .b = 36, }); + c_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, .{ .a = 37, .b = 38, }); + c_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, .{ .a = 39, .b = 40, }); + + const big_struct = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }; + c_big_struct(big_struct); + + const small = SmallStructInts{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + }; + c_small_struct_ints(small); + const small2 = c_ret_small_struct_ints(); + try expect(small2.a == 1); + try expect(small2.b == 2); + try expect(small2.c == 3); + try expect(small2.d == 4); + + const med = MedStructInts{ + .x = 1, + .y = 2, + .z = 3, + }; + c_med_struct_ints(med); + const med2 = c_ret_med_struct_ints(); + try expect(med2.x == 1); + try expect(med2.y == 2); + try expect(med2.z == 3); + + const p = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, }; + c_small_packed_struct(p); + const p2 = c_ret_small_packed_struct(); + try expect(p2.a == 0); + try expect(p2.b == 1); + try expect(p2.c == 2); + try expect(p2.d == 3); + + const split = SplitStructInt{ + .a = 1234, + .b = 100, + .c = 1337, + }; + c_split_struct_ints(split); + + const big = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }; + const big2 = c_big_struct_both(big); + try expect(big2.a == 10); + try expect(big2.b == 11); + try expect(big2.c == 12); + try expect(big2.d == 13); + try expect(big2.e == 14); + + const r1 = Rect{ + .left = 1, + .right = 21, + .top = 16, + .bottom = 4, + }; + const r2 = Rect{ + .left = 178, + .right = 189, + .top = 21, + .bottom = 15, + }; + c_multiple_struct_ints(r1, r2); + + try expect(c_ret_bool() == true); + + try expect(c_ret_u8() == 0xff); + try expect(c_ret_u16() == 0xffff); + try expect(c_ret_u32() == 0xffffffff); + try expect(c_ret_u64() == 0xffffffffffffffff); + + try expect(c_ret_s8() == -1); + try expect(c_ret_s16() == -1); + try expect(c_ret_s32() == -1); + try expect(c_ret_s64() == -1); + + c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2, }); + + const x = c_ret_struct_with_array(); + try expect(x.a == 4); + try expect(x.b == 155); + + const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined, }); + try expect(res.val == 42); + + var function_pointer = c_func_ptr_byval.&; + function_pointer(1, 2, .{ .origin = .{ .x = 9, .y = 10, .z = 11, }, .size = .{ .width = 12, .height = 13, .depth = 14, }, }, 3, 4, 5); +} + +const ByRef = struct { + val: s32, + arr: [15]s32, +}; + +const ByVal = struct { + origin: ByValOrigin, + size: ByValSize, +}; + +const ByValOrigin = struct{ + x: u64, + y: u64, + z: u64, +}; + +const ByValSize = struct{ + width: u64, + height: u64, + depth: u64, +}; + +const c_u8 :: extern = fn cc(.c) (x: u8) void; +const c_u16 :: extern = fn cc(.c) (x: u16) void; +const c_u32 :: extern = fn cc(.c) (x: u32) void; +const c_u64 :: extern = fn cc(.c) (x: u64) void; + +const c_s8 :: extern = fn cc(.c) (x: s8) void; +const c_s16 :: extern = fn cc(.c) (x: s16) void; +const c_s32 :: extern = fn cc(.c) (x: s32) void; +const c_s64 :: extern = fn cc(.c) (x: s64) void; + +const c_bool :: extern = fn cc(.c) (x: bool) void; + +const c_five_integers :: extern = fn cc(.c) (a: s32, b: s32, c: s32, d: s32, e: s32) void; + +const c_ret_struct_u64_u64 :: extern = fn cc(.c) () Struct_u64_u64; + +const c_struct_u64_u64_0 :: extern = fn cc(.c) (x: Struct_u64_u64) void; +const c_struct_u64_u64_1 :: extern = fn cc(.c) (a: usize, b: Struct_u64_u64) void; +const c_struct_u64_u64_2 :: extern = fn cc(.c) (a: usize, b: usize, c: Struct_u64_u64) void; +const c_struct_u64_u64_3 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: Struct_u64_u64) void; +const c_struct_u64_u64_4 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: Struct_u64_u64) void; +const c_struct_u64_u64_5 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: Struct_u64_u64) void; +const c_struct_u64_u64_6 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: Struct_u64_u64) void; +const c_struct_u64_u64_7 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: Struct_u64_u64) void; +const c_struct_u64_u64_8 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: Struct_u64_u64) void; + +const c_big_struct :: extern = fn cc(.c) (x: BigStruct) void; + +const c_small_struct_ints :: extern = fn cc(.c) (x: SmallStructInts) void; +const c_ret_small_struct_ints :: extern = fn cc(.c) () SmallStructInts; + +const c_med_struct_ints :: extern = fn cc(.c) (x: MedStructInts) void; +const c_ret_med_struct_ints :: extern = fn cc(.c) () MedStructInts; + +const c_small_packed_struct :: extern = fn cc(.c) (x: SmallPackedStruct) void; +const c_ret_small_packed_struct :: extern = fn cc(.c) () SmallPackedStruct; + +const c_split_struct_ints :: extern = fn cc(.c) (x: SplitStructInt) void; + +const c_big_struct_both :: extern = fn cc(.c) (x: BigStruct) BigStruct; + +const c_multiple_struct_ints :: extern = fn cc(.c) (r1: Rect, r2: Rect) void; + +const c_ret_bool :: extern = fn cc(.c) () bool; + +const c_ret_u8 :: extern = fn cc(.c) () u8; +const c_ret_u16 :: extern = fn cc(.c) () u16; +const c_ret_u32 :: extern = fn cc(.c) () u32; +const c_ret_u64 :: extern = fn cc(.c) () u64; + +const c_ret_s8 :: extern = fn cc(.c) () s8; +const c_ret_s16 :: extern = fn cc(.c) () s16; +const c_ret_s32 :: extern = fn cc(.c) () s32; +const c_ret_s64 :: extern = fn cc(.c) () s64; + +const StructWithArray = struct{ + a: s32, + padding: [4]u8, + b: s64, +}; + +const c_struct_with_array :: extern = fn cc(.c) (x: StructWithArray) void; +const c_ret_struct_with_array :: extern = fn cc(.c) () StructWithArray; +const c_modify_by_ref_param :: extern = fn cc(.c) (x: ByRef) ByRef; + +const c_func_ptr_byval :: extern = fn cc(.c) (a: usize, b: usize, c: ByVal, d: u64, e: u64, f: u64) void; + +const nat_u8 :: export = fn cc(.c) (x: u8) void { + expect(x == 0xff) catch #trap(); +} + +const nat_u16 :: export = fn cc(.c) (x: u16) void { + expect(x == 0xfffe) catch #trap(); +} + +const nat_u32 :: export = fn cc(.c) (x: u32) void { + expect(x == 0xfffffffd) catch #trap(); +} + +const nat_u64 :: export = fn cc(.c) (x: u64) void { + expect(x == 0xfffffffffffffffc) catch #trap(); +} + +const nat_s8 :: export = fn cc(.c) (x: s8) void { + expect(x == -1) catch #trap(); +} + +const nat_s16 :: export = fn cc(.c) (x: s16) void { + expect(x == -2) catch #trap(); +} + +const nat_s32 :: export = fn cc(.c) (x: s32) void { + expect(x == -3) catch #trap(); +} + +const nat_s64 :: export = fn cc(.c) (x: s64) void { + expect(x == -4) catch #trap(); +} + +// TODO: transform into a real pointer +const nat_ptr :: export = fn cc(.c) (x: usize) void { + expect(x == 0xdeadbeef) catch #trap(); +} + +const nat_five_integers :: export = fn cc(.c) (a: s32, b: s32, c: s32, d: s32, e: s32) void { + expect(a == 12) catch #trap(); + expect(b == 34) catch #trap(); + expect(c == 56) catch #trap(); + expect(d == 78) catch #trap(); + expect(e == 90) catch #trap(); +} + +const nat_bool:: export = fn cc(.c) (x: bool) void { + expect(x) catch #trap(); +} + +const Struct_u64_u64 = struct{ + a: u64, + b: u64, +}; + +const nat_ret_struct_u64_u64 :: export = fn cc(.c) () Struct_u64_u64 { + return .{ .a = 1, .b = 2, }; +} + +const nat_struct_u64_u64_0 :: export = fn cc(.c) (s: Struct_u64_u64) void { + expect(s.a == 3) catch #trap(); + expect(s.b == 4) catch #trap(); +} + +const nat_struct_u64_u64_1 :: export = fn cc(.c) (_: usize, s: Struct_u64_u64) void { + expect(s.a == 5) catch #trap(); + expect(s.b == 6) catch #trap(); +} + +const nat_struct_u64_u64_2 :: export = fn cc(.c) (_: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 7) catch #trap(); + expect(s.b == 8) catch #trap(); +} + +const nat_struct_u64_u64_3 :: export = fn cc(.c) (_: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 9) catch #trap(); + expect(s.b == 10) catch #trap(); +} + +const nat_struct_u64_u64_4 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 11) catch #trap(); + expect(s.b == 12) catch #trap(); +} + +const nat_struct_u64_u64_5 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 13) catch #trap(); + expect(s.b == 14) catch #trap(); +} + +const nat_struct_u64_u64_6 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 15) catch #trap(); + expect(s.b == 16) catch #trap(); +} + +const nat_struct_u64_u64_7 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 17) catch #trap(); + expect(s.b == 18) catch #trap(); +} + +const nat_struct_u64_u64_8 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void { + expect(s.a == 19) catch #trap(); + expect(s.b == 20) catch #trap(); +} + +const BigStruct = struct { + a: u64, + b: u64, + c: u64, + d: u64, + e: u8, +}; + +const nat_big_struct:: export = fn cc(.c) (x: BigStruct) void { + expect(x.a == 1) catch #trap(); + expect(x.b == 2) catch #trap(); + expect(x.c == 3) catch #trap(); + expect(x.d == 4) catch #trap(); + expect(x.e == 5) catch #trap(); +} + +const SmallStructInts = struct { + a: u8, + b: u8, + c: u8, + d: u8, +}; + +const nat_small_struct_ints :: export = fn cc(.c) (x: SmallStructInts) void { + expect(x.a == 1) catch #trap(); + expect(x.b == 2) catch #trap(); + expect(x.c == 3) catch #trap(); + expect(x.d == 4) catch #trap(); +} + +const MedStructInts = struct { + x: s32, + y: s32, + z: s32, +}; + +const nat_med_struct_ints :: export = fn cc(.c) (s: MedStructInts) void { + expect(s.x == 1) catch #trap(); + expect(s.y == 2) catch #trap(); + expect(s.z == 3) catch #trap(); +} + +const SmallPackedStruct = bitfield(u8) { + a: u2, + b: u2, + c: u2, + d: u2, +}; + +const nat_small_packed_struct :: export = fn cc(.c) (x: SmallPackedStruct) void { + expect(x.a == 0) catch #trap(); + expect(x.b == 1) catch #trap(); + expect(x.c == 2) catch #trap(); + expect(x.d == 3) catch #trap(); +} + +const SplitStructInt = struct { + a: u64, + b: u8, + c: u32, +}; + +const nat_split_struct_ints :: export = fn cc(.c) (x: SplitStructInt) void { + expect(x.a == 1234) catch #trap(); + expect(x.b == 100) catch #trap(); + expect(x.c == 1337) catch #trap(); +} + +const nat_big_struct_both :: export = fn cc(.c) (x: BigStruct) BigStruct { + expect(x.a == 30) catch #trap(); + expect(x.b == 31) catch #trap(); + expect(x.c == 32) catch #trap(); + expect(x.d == 33) catch #trap(); + expect(x.e == 34) catch #trap(); + const s = BigStruct{ + .a = 20, + .b = 21, + .c = 22, + .d = 23, + .e = 24, + }; + return s; +} + +const Rect = struct { + left: u32, + right: u32, + top: u32, + bottom: u32, +}; + +const nat_multiple_struct_ints :: export = fn cc(.c) (x: Rect, y: Rect) void { + expect(x.left == 1) catch #trap(); + expect(x.right == 21) catch #trap(); + expect(x.top == 16) catch #trap(); + expect(x.bottom == 4) catch #trap(); + expect(y.left == 178) catch #trap(); + expect(y.right == 189) catch #trap(); + expect(y.top == 21) catch #trap(); + expect(y.bottom == 15) catch #trap(); +} + +const nat_ret_bool :: export = fn cc(.c) () bool { + return true; +} + +const nat_ret_u8 :: export = fn cc(.c) () u8 { + return 0xff; +} + +const nat_ret_u16 :: export = fn cc(.c) () u16 { + return 0xffff; +} + +const nat_ret_u32 :: export = fn cc(.c) () u32 { + return 0xffffffff; +} + +const nat_ret_u64 :: export = fn cc(.c) () u64 { + return 0xffffffffffffffff; +} + +const nat_ret_s8 :: export = fn cc(.c) () s8 { + return -1; +} + +const nat_ret_s16 :: export = fn cc(.c) () s16 { + return -1; +} + +const nat_ret_s32 :: export = fn cc(.c) () s32 { + return -1; +} + +const nat_ret_s64 :: export = fn cc(.c) () s64 { + return -1; +} + +const nat_ret_small_struct_ints :: export = fn cc(.c) () SmallStructInts { + return .{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + }; +} + +const nat_ret_med_struct_ints :: export = fn cc(.c) () MedStructInts { + return .{ + .x = 1, + .y = 2, + .z = 3, + }; }