diff --git a/build.zig b/build.zig index 00414c3cad..4385298779 100644 --- a/build.zig +++ b/build.zig @@ -1144,7 +1144,6 @@ fn toNativePathSep(b: *std.Build, s: []const u8) []u8 { const zig_cpp_sources = [_][]const u8{ // These are planned to stay even when we are self-hosted. "src/zig_llvm.cpp", - "src/zig_clang.cpp", "src/zig_llvm-ar.cpp", "src/zig_clang_driver.cpp", "src/zig_clang_cc1_main.cpp", diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index a4f8d78374..d2affb3188 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -10,6 +10,7 @@ const CodeGenOptions = @import("../backend.zig").CodeGenOptions; const Builtins = @import("Builtins.zig"); const Builtin = Builtins.Builtin; const Diagnostics = @import("Diagnostics.zig"); +const DepFile = @import("DepFile.zig"); const LangOpts = @import("LangOpts.zig"); const Pragma = @import("Pragma.zig"); const record_layout = @import("record_layout.zig"); @@ -140,6 +141,7 @@ system_framework_dirs: std.ArrayListUnmanaged([]const u8) = .empty, /// Allocated into `gpa`, but keys are externally managed. embed_dirs: std.ArrayListUnmanaged([]const u8) = .empty, target: std.Target = @import("builtin").target, +cmodel: std.builtin.CodeModel = .default, pragma_handlers: std.StringArrayHashMapUnmanaged(*Pragma) = .{}, langopts: LangOpts = .{}, generated_buf: std.ArrayListUnmanaged(u8) = .{}, @@ -349,30 +351,206 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void { // architecture macros switch (comp.target.cpu.arch) { - .x86_64 => { - try define(w, "__amd64__"); - try define(w, "__amd64"); - try define(w, "__x86_64__"); - try define(w, "__x86_64"); + .x86, .x86_64 => { + try w.print("#define __code_model_{s}__ 1\n", .{switch (comp.cmodel) { + .default => "small", + else => @tagName(comp.cmodel), + }}); - if (comp.target.os.tag == .windows and comp.target.abi == .msvc) { - try w.writeAll( - \\#define _M_X64 100 - \\#define _M_AMD64 100 - \\ - ); + if (comp.target.cpu.arch == .x86_64) { + try define(w, "__amd64__"); + try define(w, "__amd64"); + try define(w, "__x86_64__"); + try define(w, "__x86_64"); + + if (comp.target.os.tag == .windows and comp.target.abi == .msvc) { + try w.writeAll( + \\#define _M_X64 100 + \\#define _M_AMD64 100 + \\ + ); + } + } else { + try defineStd(w, "i386", is_gnu); + + if (comp.target.os.tag == .windows and comp.target.abi == .msvc) { + try w.print("#define _M_IX86 {d}\n", .{blk: { + if (comp.target.cpu.model == &std.Target.x86.cpu.i386) break :blk 300; + if (comp.target.cpu.model == &std.Target.x86.cpu.i486) break :blk 400; + if (comp.target.cpu.model == &std.Target.x86.cpu.i586) break :blk 500; + break :blk @as(u32, 600); + }}); + } } - }, - .x86 => { - try defineStd(w, "i386", is_gnu); + try define(w, "__SEG_GS"); + try define(w, "__SEG_FS"); + try w.writeAll( + \\#define __seg_gs __attribute__((address_space(256))) + \\#define __seg_fs __attribute__((address_space(257))) + \\ + ); - if (comp.target.os.tag == .windows and comp.target.abi == .msvc) { - try w.print("#define _M_IX86 {d}\n", .{blk: { - if (comp.target.cpu.model == &std.Target.x86.cpu.i386) break :blk 300; - if (comp.target.cpu.model == &std.Target.x86.cpu.i486) break :blk 400; - if (comp.target.cpu.model == &std.Target.x86.cpu.i586) break :blk 500; - break :blk @as(u32, 600); - }}); + if (comp.target.cpu.has(.x86, .sahf) or (comp.langopts.emulate == .clang and comp.target.cpu.arch == .x86)) { + try define(w, "__LAHF_SAHF__"); + } + + const features = comp.target.cpu.features; + for ([_]struct { std.Target.x86.Feature, []const u8 }{ + .{ .aes, "__AES__" }, + .{ .vaes, "__VAES__" }, + .{ .pclmul, "__PCLMUL__" }, + .{ .vpclmulqdq, "__VPCLMULQDQ__" }, + .{ .lzcnt, "__LZCNT__" }, + .{ .rdrnd, "__RDRND__" }, + .{ .fsgsbase, "__FSGSBASE__" }, + .{ .bmi, "__BMI__" }, + .{ .bmi2, "__BMI2__" }, + .{ .popcnt, "__POPCNT__" }, + .{ .rtm, "__RTM__" }, + .{ .prfchw, "__PRFCHW__" }, + .{ .rdseed, "__RDSEED__" }, + .{ .adx, "__ADX__" }, + .{ .tbm, "__TBM__" }, + .{ .lwp, "__LWP__" }, + .{ .mwaitx, "__MWAITX__" }, + .{ .movbe, "__MOVBE__" }, + + .{ .xop, "__XOP__" }, + .{ .fma4, "__FMA4__" }, + .{ .sse4a, "__SSE4A__" }, + + .{ .fma, "__FMA__" }, + .{ .f16c, "__F16C__" }, + .{ .gfni, "__GFNI__" }, + .{ .evex512, "__EVEX512__" }, + .{ .avx10_1_256, "__AVX10_1__" }, + .{ .avx10_1_512, "__AVX10_1_512__" }, + .{ .avx10_2_256, "__AVX10_2__" }, + .{ .avx10_2_512, "__AVX10_2_512__" }, + .{ .avx512cd, "__AVX512CD__" }, + .{ .avx512vpopcntdq, "__AVX512VPOPCNTDQ__" }, + .{ .avx512vnni, "__AVX512VNNI__" }, + .{ .avx512bf16, "__AVX512BF16__" }, + .{ .avx512fp16, "__AVX512FP16__" }, + .{ .avx512dq, "__AVX512DQ__" }, + .{ .avx512bitalg, "__AVX512BITALG__" }, + .{ .avx512bw, "__AVX512BW__" }, + + .{ .avx512vl, "__AVX512VL__" }, + .{ .avx512vl, "__EVEX256__" }, + + .{ .avx512vbmi, "__AVX512VBMI__" }, + .{ .avx512vbmi2, "__AVX512VBMI2__" }, + .{ .avx512ifma, "__AVX512IFMA__" }, + .{ .avx512vp2intersect, "__AVX512VP2INTERSECT__" }, + .{ .sha, "__SHA__" }, + .{ .sha512, "__SHA512__" }, + .{ .fxsr, "__FXSR__" }, + .{ .xsave, "__XSAVE__" }, + .{ .xsaveopt, "__XSAVEOPT__" }, + .{ .xsavec, "__XSAVEC__" }, + .{ .xsaves, "__XSAVES__" }, + .{ .pku, "__PKU__" }, + .{ .clflushopt, "__CLFLUSHOPT__" }, + .{ .clwb, "__CLWB__" }, + .{ .wbnoinvd, "__WBNOINVD__" }, + .{ .shstk, "__SHSTK__" }, + .{ .sgx, "__SGX__" }, + .{ .sm3, "__SM3__" }, + .{ .sm4, "__SM4__" }, + .{ .prefetchi, "__PREFETCHI__" }, + .{ .clzero, "__CLZERO__" }, + .{ .kl, "__KL__" }, + .{ .widekl, "__WIDEKL__" }, + .{ .rdpid, "__RDPID__" }, + .{ .rdpru, "__RDPRU__" }, + .{ .cldemote, "__CLDEMOTE__" }, + .{ .waitpkg, "__WAITPKG__" }, + .{ .movdiri, "__MOVDIRI__" }, + .{ .movdir64b, "__MOVDIR64B__" }, + .{ .movrs, "__MOVRS__" }, + .{ .pconfig, "__PCONFIG__" }, + .{ .ptwrite, "__PTWRITE__" }, + .{ .invpcid, "__INVPCID__" }, + .{ .enqcmd, "__ENQCMD__" }, + .{ .hreset, "__HRESET__" }, + .{ .amx_tile, "__AMX_TILE__" }, + .{ .amx_int8, "__AMX_INT8__" }, + .{ .amx_bf16, "__AMX_BF16__" }, + .{ .amx_fp16, "__AMX_FP16__" }, + .{ .amx_complex, "__AMX_COMPLEX__" }, + .{ .amx_fp8, "__AMX_FP8__" }, + .{ .amx_movrs, "__AMX_MOVRS__" }, + .{ .amx_transpose, "__AMX_TRANSPOSE__" }, + .{ .amx_avx512, "__AMX_AVX512__" }, + .{ .amx_tf32, "__AMX_TF32__" }, + .{ .cmpccxadd, "__CMPCCXADD__" }, + .{ .raoint, "__RAOINT__" }, + .{ .avxifma, "__AVXIFMA__" }, + .{ .avxneconvert, "__AVXNECONVERT__" }, + .{ .avxvnni, "__AVXVNNI__" }, + .{ .avxvnniint16, "__AVXVNNIINT16__" }, + .{ .avxvnniint8, "__AVXVNNIINT8__" }, + .{ .serialize, "__SERIALIZE__" }, + .{ .tsxldtrk, "__TSXLDTRK__" }, + .{ .uintr, "__UINTR__" }, + .{ .usermsr, "__USERMSR__" }, + .{ .crc32, "__CRC32__" }, + .{ .egpr, "__EGPR__" }, + .{ .push2pop2, "__PUSH2POP2__" }, + .{ .ppx, "__PPX__" }, + .{ .ndd, "__NDD__" }, + .{ .ccmp, "__CCMP__" }, + .{ .nf, "__NF__" }, + .{ .cf, "__CF__" }, + .{ .zu, "__ZU__" }, + + .{ .avx512f, "__AVX512F__" }, + .{ .avx2, "__AVX2__" }, + .{ .avx, "__AVX__" }, + .{ .sse4_2, "__SSE4_2__" }, + .{ .sse4_1, "__SSE4_1__" }, + .{ .ssse3, "__SSSE3__" }, + .{ .sse3, "__SSE3__" }, + .{ .sse2, "__SSE2__" }, + .{ .sse, "__SSE__" }, + .{ .sse, "__SSE_MATH__" }, + + .{ .mmx, "__MMX__" }, + }) |fs| { + if (features.isEnabled(@intFromEnum(fs[0]))) { + try define(w, fs[1]); + } + } + + if (comp.langopts.ms_extensions and comp.target.cpu.arch == .x86) { + const level = if (comp.target.cpu.has(.x86, .sse2)) + "2" + else if (comp.target.cpu.has(.x86, .sse)) + "1" + else + "0"; + + try w.print("#define _M_IX86_FP {s}\n", .{level}); + } + + if (comp.target.cpu.hasAll(.x86, &.{ .egpr, .push2pop2, .ppx, .ndd, .ccmp, .nf, .cf, .zu })) { + try define(w, "__APX_F__"); + } + + if (comp.target.cpu.hasAll(.x86, &.{ .egpr, .inline_asm_use_gpr32 })) { + try define(w, "__APX_INLINE_ASM_USE_GPR32__"); + } + + if (comp.target.cpu.has(.x86, .cx8)) { + try define(w, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } + if (comp.target.cpu.has(.x86, .cx16) and comp.target.cpu.arch == .x86_64) { + try define(w, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } + + if (comp.hasFloat128()) { + try w.writeAll("#define __SIZEOF_FLOAT128__ 16\n"); } }, .mips, @@ -443,13 +621,132 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void { try define(w, "__arm64__"); } if (comp.target.os.tag == .windows and comp.target.abi == .msvc) { - try w.writeAll("#define _M_ARM64 100\n"); + try w.writeAll("#define _M_ARM64 1\n"); + } + + { + const cmodel = switch (comp.cmodel) { + .default => "small", + else => @tagName(comp.cmodel), + }; + try w.writeAll("#define __AARCH64_CMODEL_"); + for (cmodel) |c| { + try w.writeByte(std.ascii.toUpper(c)); + } + try w.writeAll("__ 1\n"); + } + + if (comp.target.cpu.has(.aarch64, .fp_armv8)) { + try w.writeAll("#define __ARM_FP 0xE\n"); + } + if (comp.target.cpu.has(.aarch64, .neon)) { + try define(w, "__ARM_NEON"); + try w.writeAll("#define __ARM_NEON_FP 0xE\n"); + } + if (comp.target.cpu.has(.aarch64, .bf16)) { + try define(w, "__ARM_FEATURE_BF16"); + try define(w, "__ARM_FEATURE_BF16_VECTOR_ARITHMETIC"); + try define(w, "__ARM_BF16_FORMAT_ALTERNATIVE"); + try define(w, "__ARM_FEATURE_BF16_SCALAR_ARITHMETIC"); + if (comp.target.cpu.has(.aarch64, .sve)) { + try define(w, "__ARM_FEATURE_SVE_BF16"); + } + } + if (comp.target.cpu.hasAll(.aarch64, &.{ .sve2, .sve_aes })) { + try define(w, "__ARM_FEATURE_SVE2_AES"); + } + if (comp.target.cpu.hasAll(.aarch64, &.{ .sve2, .sve_bitperm })) { + try define(w, "__ARM_FEATURE_SVE2_BITPERM"); + } + if (comp.target.cpu.has(.aarch64, .sme)) { + try define(w, "__ARM_FEATURE_SME"); + try define(w, "__ARM_FEATURE_LOCALLY_STREAMING"); + } + if (comp.target.cpu.has(.aarch64, .fmv)) { + try define(w, "__HAVE_FUNCTION_MULTI_VERSIONING"); + } + if (comp.target.cpu.has(.aarch64, .sha3)) { + try define(w, "__ARM_FEATURE_SHA3"); + try define(w, "__ARM_FEATURE_SHA512"); + } + if (comp.target.cpu.has(.aarch64, .sm4)) { + try define(w, "__ARM_FEATURE_SM3"); + try define(w, "__ARM_FEATURE_SM4"); + } + if (!comp.target.cpu.has(.aarch64, .strict_align)) { + try define(w, "__ARM_FEATURE_UNALIGNED"); + } + if (comp.target.cpu.hasAll(.aarch64, &.{ .neon, .fullfp16 })) { + try define(w, "__ARM_FEATURE_FP16_VECTOR_ARITHMETIC"); + } + if (comp.target.cpu.has(.aarch64, .rcpc3)) { + try w.writeAll("#define __ARM_FEATURE_RCPC 3\n"); + } else if (comp.target.cpu.has(.aarch64, .rcpc)) { + try define(w, "__ARM_FEATURE_RCPC"); + } + + const features = comp.target.cpu.features; + for ([_]struct { std.Target.aarch64.Feature, []const u8 }{ + .{ .sve, "SVE" }, + .{ .sve2, "SVE2" }, + .{ .sve2p1, "SVE2p1" }, + .{ .sve2_sha3, "SVE2_SHA3" }, + .{ .sve2_sm4, "SVE2_SM4" }, + .{ .sve_b16b16, "SVE_B16B16" }, + .{ .sme2, "SME2" }, + .{ .sme2p1, "SME2p1" }, + .{ .sme_f16f16, "SME_F16F16" }, + .{ .sme_b16b16, "SME_B16B16" }, + .{ .crc, "CRC32" }, + .{ .aes, "AES" }, + .{ .sha2, "SHA2" }, + .{ .pauth, "PAUTH" }, + .{ .pauth_lr, "PAUTH_LR" }, + .{ .bti, "BTI" }, + .{ .fullfp16, "FP16_SCALAR_ARITHMETIC" }, + .{ .dotprod, "DOTPROD" }, + .{ .mte, "MEMORY_TAGGING" }, + .{ .tme, "TME" }, + .{ .i8mm, "MATMUL_INT8" }, + .{ .lse, "ATOMICS" }, + .{ .f64mm, "SVE_MATMUL_FP64" }, + .{ .f32mm, "SVE_MATMUL_FP32" }, + .{ .i8mm, "SVE_MATMUL_INT8" }, + .{ .fp16fml, "FP16_FML" }, + .{ .ls64, "LS64" }, + .{ .rand, "RNG" }, + .{ .mops, "MOPS" }, + .{ .d128, "SYSREG128" }, + .{ .gcs, "GCS" }, + }) |fs| { + if (features.isEnabled(@intFromEnum(fs[0]))) { + try w.print("#define __ARM_FEATURE_{s} 1\n", .{fs[1]}); + } } }, .msp430 => { try define(w, "MSP430"); try define(w, "__MSP430__"); }, + .arc => { + try define(w, "__arc__"); + }, + .wasm32, .wasm64 => { + try define(w, "__wasm"); + try define(w, "__wasm__"); + if (comp.target.cpu.arch == .wasm32) { + try define(w, "__wasm32"); + try define(w, "__wasm32__"); + } else { + try define(w, "__wasm64"); + try define(w, "__wasm64__"); + } + + for (comp.target.cpu.arch.allFeaturesList()) |feature| { + if (!comp.target.cpu.features.isEnabled(feature.index)) continue; + try w.print("#define __wasm_{s}__ 1\n", .{feature.name}); + } + }, else => {}, } @@ -1477,7 +1774,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: std.Io.Limit) ![ var file_buf: [4096]u8 = undefined; var file_reader = file.reader(&file_buf); - if (limit.minInt(try file_reader.getSize()) > std.math.maxInt(u32)) return error.FileTooBig; + if (limit.minInt64(try file_reader.getSize()) > std.math.maxInt(u32)) return error.FileTooBig; _ = allocating.writer.sendFileAll(&file_reader, limit) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, @@ -1494,14 +1791,16 @@ pub fn findEmbed( /// angle bracket vs quotes include_type: IncludeType, limit: std.Io.Limit, + opt_dep_file: ?*DepFile, ) !?[]const u8 { if (std.fs.path.isAbsolute(filename)) { - return if (comp.getFileContents(filename, limit)) |some| - some - else |err| switch (err) { + if (comp.getFileContents(filename, limit)) |some| { + if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename); + return some; + } else |err| switch (err) { error.OutOfMemory => |e| return e, - else => null, - }; + else => return null, + } } var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa); @@ -1516,6 +1815,7 @@ pub fn findEmbed( std.mem.replaceScalar(u8, path, '\\', '/'); } if (comp.getFileContents(path, limit)) |some| { + if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename); return some; } else |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, @@ -1531,6 +1831,7 @@ pub fn findEmbed( std.mem.replaceScalar(u8, path, '\\', '/'); } if (comp.getFileContents(path, limit)) |some| { + if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename); return some; } else |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, diff --git a/lib/compiler/aro/aro/DepFile.zig b/lib/compiler/aro/aro/DepFile.zig new file mode 100644 index 0000000000..6aee5918b2 --- /dev/null +++ b/lib/compiler/aro/aro/DepFile.zig @@ -0,0 +1,78 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +pub const Format = enum { make, nmake }; + +const DepFile = @This(); + +target: []const u8, +deps: std.StringArrayHashMapUnmanaged(void) = .empty, +format: Format, + +pub fn deinit(d: *DepFile, gpa: Allocator) void { + d.deps.deinit(gpa); + d.* = undefined; +} + +pub fn addDependency(d: *DepFile, gpa: Allocator, path: []const u8) !void { + try d.deps.put(gpa, path, {}); +} + +pub fn addDependencyDupe(d: *DepFile, gpa: Allocator, arena: Allocator, path: []const u8) !void { + const gop = try d.deps.getOrPut(gpa, path); + if (gop.found_existing) return; + gop.key_ptr.* = try arena.dupe(u8, path); +} + +pub fn write(d: *const DepFile, w: *std.Io.Writer) std.Io.Writer.Error!void { + const max_columns = 75; + var columns: usize = 0; + + try w.writeAll(d.target); + columns += d.target.len; + try w.writeByte(':'); + columns += 1; + + for (d.deps.keys()) |path| { + if (std.mem.eql(u8, path, "")) continue; + + if (columns + path.len + " \\\n".len > max_columns) { + try w.writeAll(" \\\n "); + columns = 1; + } + try w.writeByte(' '); + try d.writePath(path, w); + columns += path.len + 1; + } + try w.writeByte('\n'); + try w.flush(); +} + +fn writePath(d: *const DepFile, path: []const u8, w: *std.Io.Writer) !void { + switch (d.format) { + .nmake => { + if (std.mem.indexOfAny(u8, path, " #${}^!")) |_| + try w.print("\"{s}\"", .{path}) + else + try w.writeAll(path); + }, + .make => { + for (path, 0..) |c, i| { + if (c == '#') { + try w.writeByte('\\'); + } else if (c == '$') { + try w.writeByte('$'); + } else if (c == ' ') { + try w.writeByte('\\'); + var j = i; + while (j != 0) { + j -= 1; + if (path[j] != '\\') break; + try w.writeByte('\\'); + } + } + try w.writeByte(c); + } + }, + } +} diff --git a/lib/compiler/aro/aro/Diagnostics.zig b/lib/compiler/aro/aro/Diagnostics.zig index 4c3be51185..3a07d85707 100644 --- a/lib/compiler/aro/aro/Diagnostics.zig +++ b/lib/compiler/aro/aro/Diagnostics.zig @@ -23,6 +23,52 @@ pub const Message = struct { @"error", @"fatal error", }; + + pub fn write(msg: Message, w: *std.Io.Writer, config: std.Io.tty.Config, details: bool) std.Io.tty.Config.SetColorError!void { + try config.setColor(w, .bold); + if (msg.location) |loc| { + try w.print("{s}:{d}:{d}: ", .{ loc.path, loc.line_no, loc.col }); + } + switch (msg.effective_kind) { + .@"fatal error", .@"error" => try config.setColor(w, .bright_red), + .note => try config.setColor(w, .bright_cyan), + .warning => try config.setColor(w, .bright_magenta), + .off => unreachable, + } + try w.print("{s}: ", .{@tagName(msg.effective_kind)}); + + try config.setColor(w, .white); + try w.writeAll(msg.text); + if (msg.opt) |some| { + if (msg.effective_kind == .@"error" and msg.kind != .@"error") { + try w.print(" [-Werror,-W{s}]", .{@tagName(some)}); + } else if (msg.effective_kind != .note) { + try w.print(" [-W{s}]", .{@tagName(some)}); + } + } else if (msg.extension) { + if (msg.effective_kind == .@"error") { + try w.writeAll(" [-Werror,-Wpedantic]"); + } else if (msg.effective_kind != msg.kind) { + try w.writeAll(" [-Wpedantic]"); + } + } + + if (!details or msg.location == null) { + try w.writeAll("\n"); + try config.setColor(w, .reset); + } else { + const loc = msg.location.?; + const trailer = if (loc.end_with_splice) "\\ " else ""; + try config.setColor(w, .reset); + try w.print("\n{s}{s}\n", .{ loc.line, trailer }); + try w.splatByteAll(' ', loc.width); + try config.setColor(w, .bold); + try config.setColor(w, .bright_green); + try w.writeAll("^\n"); + try config.setColor(w, .reset); + } + try w.flush(); + } }; pub const Option = enum { @@ -247,6 +293,11 @@ output: union(enum) { }, ignore, }, +/// Force usage of color in output. +color: ?bool = null, +/// Include line of code in output. +details: bool = true, + state: State = .{}, /// Amount of error or fatal error messages that have been sent to `output`. errors: u32 = 0, @@ -468,7 +519,10 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void { switch (d.output) { .ignore => {}, .to_writer => |writer| { - writeToWriter(msg, writer.writer, writer.color) catch { + var config = writer.color; + if (d.color == false) config = .no_color; + if (d.color == true and config == .no_color) config = .escape_codes; + msg.write(writer.writer, config, d.details) catch { return error.FatalError; }; }, @@ -485,48 +539,3 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void { }, } } - -pub fn writeToWriter(msg: Message, w: *std.Io.Writer, config: std.Io.tty.Config) !void { - try config.setColor(w, .bold); - if (msg.location) |loc| { - try w.print("{s}:{d}:{d}: ", .{ loc.path, loc.line_no, loc.col }); - } - switch (msg.effective_kind) { - .@"fatal error", .@"error" => try config.setColor(w, .bright_red), - .note => try config.setColor(w, .bright_cyan), - .warning => try config.setColor(w, .bright_magenta), - .off => unreachable, - } - try w.print("{s}: ", .{@tagName(msg.effective_kind)}); - - try config.setColor(w, .white); - try w.writeAll(msg.text); - if (msg.opt) |some| { - if (msg.effective_kind == .@"error" and msg.kind != .@"error") { - try w.print(" [-Werror,-W{s}]", .{@tagName(some)}); - } else if (msg.effective_kind != .note) { - try w.print(" [-W{s}]", .{@tagName(some)}); - } - } else if (msg.extension) { - if (msg.effective_kind == .@"error") { - try w.writeAll(" [-Werror,-Wpedantic]"); - } else if (msg.effective_kind != msg.kind) { - try w.writeAll(" [-Wpedantic]"); - } - } - - if (msg.location) |loc| { - const trailer = if (loc.end_with_splice) "\\ " else ""; - try config.setColor(w, .reset); - try w.print("\n{s}{s}\n", .{ loc.line, trailer }); - try w.splatByteAll(' ', loc.width); - try config.setColor(w, .bold); - try config.setColor(w, .bright_green); - try w.writeAll("^\n"); - try config.setColor(w, .reset); - } else { - try w.writeAll("\n"); - try config.setColor(w, .reset); - } - try w.flush(); -} diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index c468958aa5..2960d70328 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -10,6 +10,7 @@ const Object = backend.Object; const Compilation = @import("Compilation.zig"); const Diagnostics = @import("Diagnostics.zig"); +const DepFile = @import("DepFile.zig"); const GCCVersion = @import("Driver/GCCVersion.zig"); const LangOpts = @import("LangOpts.zig"); const Preprocessor = @import("Preprocessor.zig"); @@ -63,7 +64,6 @@ verbose_ast: bool = false, verbose_pp: bool = false, verbose_ir: bool = false, verbose_linker_args: bool = false, -color: ?bool = null, nobuiltininc: bool = false, nostdinc: bool = false, nostdlibinc: bool = false, @@ -73,7 +73,6 @@ mabicalls: ?bool = null, dynamic_nopic: ?bool = null, ropi: bool = false, rwpi: bool = false, -cmodel: std.builtin.CodeModel = .default, debug_dump_letters: packed struct(u3) { d: bool = false, m: bool = false, @@ -88,17 +87,27 @@ debug_dump_letters: packed struct(u3) { return .result_only; } } = .{}, +dependencies: struct { + m: bool = false, + md: bool = false, + format: DepFile.Format = .make, + file: ?[]const u8 = null, +} = .{}, /// Full path to the aro executable aro_name: []const u8 = "", -/// Value of --triple= passed via CLI +/// Value of -target passed via CLI raw_target_triple: ?[]const u8 = null, +/// Value of -mcpu passed via CLI +raw_cpu: ?[]const u8 = null, + /// Non-optimizing assembly backend is currently selected by passing `-O0` use_assembly_backend: bool = false, // linker options +use_linker: ?[]const u8 = null, linker_path: ?[]const u8 = null, nodefaultlibs: bool = false, nolibc: bool = false, @@ -133,13 +142,26 @@ pub const usage = \\ --help Print this message \\ --version Print aro version \\ - \\Compile options: - \\ -c, --compile Only run preprocess, compile, and assemble steps + \\Preprocessor options: + \\ -C Do not discard comments + \\ -CC Do not discard comments, including in macro expansions \\ -dM Output #define directives for all the macros defined during the execution of the preprocessor \\ -dD Like -dM except that it outputs both the #define directives and the result of preprocessing \\ -dN Like -dD, but emit only the macro names, not their expansions. \\ -D = Define to (defaults to 1) \\ -E Only run the preprocessor + \\ -fdollars-in-identifiers + \\ Allow '$' in identifiers + \\ -fno-dollars-in-identifiers + \\ Disallow '$' in identifiers + \\ -M Output dependency file instead of preprocessing result + \\ -MD Like -M except -E is not implied + \\ -MF Write dependency file to + \\ -MV Use NMake/Jom format for dependency file + \\ -P, --no-line-commands Disable linemarker output in -E mode + \\ + \\Compile options: + \\ -c, --compile Only run preprocess, compile, and assemble steps \\ -fapple-kext Use Apple's kernel extensions ABI \\ -fchar8_t Enable char8_t (enabled by default in C23 and later) \\ -fno-char8_t Disable char8_t (disabled by default for pre-C23) @@ -158,10 +180,6 @@ pub const usage = \\ -fhosted Compilation in a hosted environment \\ -fms-extensions Enable support for Microsoft extensions \\ -fno-ms-extensions Disable support for Microsoft extensions - \\ -fdollars-in-identifiers - \\ Allow '$' in identifiers - \\ -fno-dollars-in-identifiers - \\ Disallow '$' in identifiers \\ -g Generate debug information \\ -fmacro-backtrace-limit= \\ Set limit on how many macro expansion traces are shown in errors (default 6) @@ -197,6 +215,7 @@ pub const usage = \\ -mabicalls Enable SVR4-style position-independent code (Mips only) \\ -mno-abicalls Disable SVR4-style position-independent code (Mips only) \\ -mcmodel= Generate code for the given code model + \\ -mcpu [cpu] Specify target CPU and feature set \\ -mkernel Enable kernel development mode \\ -nobuiltininc Do not search the compiler's builtin directory for include files \\ -resource-dir Override the path to the compiler's builtin resource directory @@ -204,7 +223,6 @@ pub const usage = \\ Do not search the standard system directories or compiler builtin directories for include files. \\ -nostdlibinc Do not search the standard system directories for include files, but do search compiler builtin include directories \\ -o Write output to - \\ -P, --no-line-commands Disable linemarker output in -E mode \\ -pedantic Warn on language extensions \\ -pedantic-errors Error on language extensions \\ --rtlib= Compiler runtime library to use (libgcc or compiler-rt) @@ -262,9 +280,12 @@ pub fn parseArgs( var pic_arg: []const u8 = ""; var declspec_attrs: ?bool = null; var ms_extensions: ?bool = null; + var strip = true; + var debug: ?backend.CodeGenOptions.DebugFormat = null; + var emulate: ?LangOpts.Compiler = null; while (i < args.len) : (i += 1) { const arg = args[i]; - if (mem.startsWith(u8, arg, "-") and arg.len > 1) { + if (arg.len > 1 and arg[0] == '-') { if (mem.eql(u8, arg, "--help")) { try stdout.print(usage, .{args[0]}); try stdout.flush(); @@ -329,7 +350,7 @@ pub fn parseArgs( } else if (mem.eql(u8, arg, "-fapple-kext")) { d.apple_kext = true; } else if (option(arg, "-mcmodel=")) |cmodel| { - d.cmodel = std.meta.stringToEnum(std.builtin.CodeModel, cmodel) orelse + d.comp.cmodel = std.meta.stringToEnum(std.builtin.CodeModel, cmodel) orelse return d.fatal("unsupported machine code model: '{s}'", .{arg}); } else if (mem.eql(u8, arg, "-mkernel")) { d.mkernel = true; @@ -339,14 +360,47 @@ pub fn parseArgs( d.mabicalls = true; } else if (mem.eql(u8, arg, "-mno-abicalls")) { d.mabicalls = false; + } else if (mem.eql(u8, arg, "-mcpu")) { + i += 1; + if (i >= args.len) { + try d.err("expected argument after -mcpu", .{}); + continue; + } + d.raw_cpu = args[i]; + } else if (option(arg, "-mcpu=")) |cpu| { + d.raw_cpu = cpu; + } else if (mem.eql(u8, arg, "-M") or mem.eql(u8, arg, "--dependencies")) { + d.dependencies.m = true; + // -M implies -w and -E + d.diagnostics.state.ignore_warnings = true; + d.only_preprocess = true; + } else if (mem.eql(u8, arg, "-MD") or mem.eql(u8, arg, "--write-dependencies")) { + d.dependencies.md = true; + } else if (mem.startsWith(u8, arg, "-MF")) { + var path = arg["-MF".len..]; + if (path.len == 0) { + i += 1; + if (i >= args.len) { + try d.err("expected argument after -MF", .{}); + continue; + } + path = args[i]; + } + d.dependencies.file = path; + } else if (mem.eql(u8, arg, "-MV")) { + d.dependencies.format = .nmake; } else if (mem.eql(u8, arg, "-fchar8_t")) { d.comp.langopts.has_char8_t_override = true; } else if (mem.eql(u8, arg, "-fno-char8_t")) { d.comp.langopts.has_char8_t_override = false; } else if (mem.eql(u8, arg, "-fcolor-diagnostics")) { - d.color = true; + d.diagnostics.color = true; } else if (mem.eql(u8, arg, "-fno-color-diagnostics")) { - d.color = false; + d.diagnostics.color = false; + } else if (mem.eql(u8, arg, "-fcaret-diagnostics")) { + d.diagnostics.details = true; + } else if (mem.eql(u8, arg, "-fno-caret-diagnostics")) { + d.diagnostics.details = false; } else if (mem.eql(u8, arg, "-fcommon")) { d.comp.code_gen_options.common = true; } else if (mem.eql(u8, arg, "-fno-common")) { @@ -356,9 +410,31 @@ pub fn parseArgs( } else if (mem.eql(u8, arg, "-fno-dollars-in-identifiers")) { d.comp.langopts.dollars_in_identifiers = false; } else if (mem.eql(u8, arg, "-g")) { - d.comp.code_gen_options.debug = true; + strip = false; } else if (mem.eql(u8, arg, "-g0")) { - d.comp.code_gen_options.debug = false; + strip = true; + } else if (mem.eql(u8, arg, "-gcodeview")) { + debug = .code_view; + } else if (mem.eql(u8, arg, "-gdwarf32")) { + debug = .{ .dwarf = .@"32" }; + } else if (mem.eql(u8, arg, "-gdwarf64")) { + debug = .{ .dwarf = .@"64" }; + } else if (mem.eql(u8, arg, "-gdwarf") or + mem.eql(u8, arg, "-gdwarf-2") or + mem.eql(u8, arg, "-gdwarf-3") or + mem.eql(u8, arg, "-gdwarf-4") or + mem.eql(u8, arg, "-gdwarf-5")) + { + d.comp.code_gen_options.dwarf_version = switch (arg[arg.len - 1]) { + '2' => .@"2", + '3' => .@"3", + '4' => .@"4", + '5' => .@"5", + else => .@"0", + }; + if (debug == null or debug.? != .dwarf) { + debug = .{ .dwarf = .@"32" }; + } } else if (mem.eql(u8, arg, "-fdigraphs")) { d.comp.langopts.digraphs = true; } else if (mem.eql(u8, arg, "-fno-digraphs")) { @@ -413,9 +489,9 @@ pub fn parseArgs( ms_extensions = true; } else if (mem.eql(u8, arg, "-fno-ms-extensions")) { ms_extensions = false; - } else if (mem.startsWith(u8, arg, "-fsyntax-only")) { + } else if (mem.eql(u8, arg, "-fsyntax-only")) { d.only_syntax = true; - } else if (mem.startsWith(u8, arg, "-fno-syntax-only")) { + } else if (mem.eql(u8, arg, "-fno-syntax-only")) { d.only_syntax = false; } else if (mem.eql(u8, arg, "-fgnuc-version=")) { gnuc_version = "0"; @@ -483,12 +559,7 @@ pub fn parseArgs( try d.err("invalid compiler '{s}'", .{arg}); continue; }; - d.comp.langopts.setEmulatedCompiler(compiler); - switch (d.comp.langopts.emulate) { - .clang => try d.diagnostics.set("clang", .off), - .gcc => try d.diagnostics.set("gnu", .off), - .msvc => try d.diagnostics.set("microsoft", .off), - } + emulate = compiler; } else if (option(arg, "-ffp-eval-method=")) |fp_method_str| { const fp_eval_method = std.meta.stringToEnum(LangOpts.FPEvalMethod, fp_method_str) orelse .indeterminate; if (fp_eval_method == .indeterminate) { @@ -554,8 +625,10 @@ pub fn parseArgs( continue; } d.raw_target_triple = args[i]; + emulate = null; } else if (option(arg, "--target=")) |triple| { d.raw_target_triple = triple; + emulate = null; } else if (mem.eql(u8, arg, "--verbose-ast")) { d.verbose_ast = true; } else if (mem.eql(u8, arg, "--verbose-pp")) { @@ -571,6 +644,10 @@ pub fn parseArgs( d.comp.langopts.preserve_comments = true; d.comp.langopts.preserve_comments_in_macros = true; comment_arg = arg; + } else if (option(arg, "-fuse-ld=")) |linker_name| { + d.use_linker = linker_name; + } else if (mem.eql(u8, arg, "-fuse-ld=")) { + d.use_linker = null; } else if (option(arg, "--ld-path=")) |linker_path| { d.linker_path = linker_path; } else if (mem.eql(u8, arg, "-r")) { @@ -624,6 +701,33 @@ pub fn parseArgs( } else { try d.err("invalid unwind library name '{s}'", .{unwindlib}); } + } else if (mem.startsWith(u8, arg, "-x")) { + var lang = arg["-x".len..]; + if (lang.len == 0) { + i += 1; + if (i >= args.len) { + try d.err("expected argument after -x", .{}); + continue; + } + lang = args[i]; + } + if (!mem.eql(u8, lang, "none") and !mem.eql(u8, lang, "c")) { + try d.err("language not recognized: '{s}'", .{lang}); + } + } else if (mem.startsWith(u8, arg, "-flto")) { + const rest = arg["-flto".len..]; + if (rest.len == 0 or + mem.eql(u8, rest, "=auto") or + mem.eql(u8, rest, "=full") or + mem.eql(u8, rest, "=jobserver") or + mem.eql(u8, rest, "=thin")) + { + try d.warn("lto not supported", .{}); + } else { + return d.fatal("invalid lto mode: '{s}'", .{arg}); + } + } else if (mem.eql(u8, arg, "-fno-lto")) { + // nothing to do } else { try d.warn("unknown argument '{s}'", .{arg}); } @@ -636,17 +740,33 @@ pub fn parseArgs( try d.inputs.append(d.comp.gpa, source); } } - if (d.raw_target_triple) |triple| triple: { - const query = std.Target.Query.parse(.{ .arch_os_abi = triple }) catch { - try d.err("invalid target '{s}'", .{triple}); - d.raw_target_triple = null; - break :triple; + { + var diags: std.Target.Query.ParseOptions.Diagnostics = .{}; + const opts: std.Target.Query.ParseOptions = .{ + .arch_os_abi = d.raw_target_triple orelse "native", + .cpu_features = d.raw_cpu, + .diagnostics = &diags, }; - const target = std.zig.system.resolveTargetQuery(query) catch |e| { + const query = std.Target.Query.parse(opts) catch |er| switch (er) { + error.UnknownCpuModel => { + return d.fatal("unknown CPU: '{s}'", .{diags.cpu_name.?}); + }, + error.UnknownCpuFeature => { + return d.fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?}); + }, + error.UnknownArchitecture => { + return d.fatal("unknown architecture: '{s}'", .{diags.unknown_architecture_name.?}); + }, + else => |e| return d.fatal("unable to parse target query '{s}': {s}", .{ + opts.arch_os_abi, @errorName(e), + }), + }; + d.comp.target = std.zig.system.resolveTargetQuery(query) catch |e| { return d.fatal("unable to resolve target: {s}", .{errorDescription(e)}); }; - d.comp.target = target; - d.comp.langopts.setEmulatedCompiler(target_util.systemCompiler(target)); + } + if (emulate != null or d.raw_target_triple != null) { + d.comp.langopts.setEmulatedCompiler(emulate orelse target_util.systemCompiler(d.comp.target)); switch (d.comp.langopts.emulate) { .clang => try d.diagnostics.set("clang", .off), .gcc => try d.diagnostics.set("gnu", .off), @@ -673,6 +793,19 @@ pub fn parseArgs( const pic_level, const is_pie = try d.getPICMode(pic_arg); d.comp.code_gen_options.pic_level = pic_level; d.comp.code_gen_options.is_pie = is_pie; + d.comp.code_gen_options.debug = debug: { + if (strip) break :debug .strip; + if (debug) |explicit| break :debug explicit; + break :debug switch (d.comp.target.ofmt) { + .elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" }, + .coff => .code_view, + .c => switch (d.comp.target.os.tag) { + .windows, .uefi => .code_view, + else => .{ .dwarf = .@"32" }, + }, + .spirv, .hex, .raw, .plan9 => .strip, + }; + }; if (declspec_attrs) |some| d.comp.langopts.declspec_attrs = some; if (ms_extensions) |some| d.comp.langopts.setMSExtensions(some); return false; @@ -728,6 +861,7 @@ pub fn fatal(d: *Driver, comptime fmt: []const u8, args: anytype) error{ FatalEr } pub fn printDiagnosticsStats(d: *Driver) void { + if (!d.diagnostics.details) return; const warnings = d.diagnostics.warnings; const errors = d.diagnostics.errors; @@ -743,14 +877,14 @@ pub fn printDiagnosticsStats(d: *Driver) void { } pub fn detectConfig(d: *Driver, file: std.fs.File) std.Io.tty.Config { - if (d.color == true) return .escape_codes; - if (d.color == false) return .no_color; + if (d.diagnostics.color == false) return .no_color; + const force_color = d.diagnostics.color == true; if (file.supportsAnsiEscapeCodes()) return .escape_codes; if (@import("builtin").os.tag == .windows and file.isTty()) { var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; - if (std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != std.os.windows.TRUE) { - return .no_color; + if (std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == std.os.windows.FALSE) { + return if (force_color) .escape_codes else .no_color; } return .{ .windows_api = .{ .handle = file.handle, @@ -758,7 +892,7 @@ pub fn detectConfig(d: *Driver, file: std.fs.File) std.Io.tty.Config { } }; } - return .no_color; + return if (force_color) .escape_codes else .no_color; } pub fn errorDescription(e: anyerror) []const u8 { @@ -851,6 +985,47 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_ if (fast_exit) std.process.exit(0); } +/// Initializes a DepFile if requested by driver options. +pub fn initDepFile(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u8) Compilation.Error!?DepFile { + if (!d.dependencies.m and !d.dependencies.md) return null; + var dep_file: DepFile = .{ + .target = undefined, + .format = d.dependencies.format, + }; + + if (d.dependencies.md and d.output_name != null) { + dep_file.target = d.output_name.?; + } else { + const args = .{ + std.fs.path.stem(source.path), + d.comp.target.ofmt.fileExt(d.comp.target.cpu.arch), + }; + dep_file.target = std.fmt.bufPrint(buf, "{s}{s}", args) catch + return d.fatal("dependency file name too long for filesystem '{s}{s}'", args); + } + + try dep_file.addDependency(d.comp.gpa, source.path); + errdefer comptime unreachable; + + return dep_file; +} + +/// Returns name requested for the dependency file or null for stdout. +pub fn getDepFileName(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u8) Compilation.Error!?[]const u8 { + if (d.dependencies.file) |file| { + if (std.mem.eql(u8, file, "-")) return null; + return file; + } + if (!d.dependencies.md) { + if (d.output_name) |name| return name; + return null; + } + + const base_name = std.fs.path.stem(d.output_name orelse source.path); + return std.fmt.bufPrint(buf, "{s}.d", .{base_name}) catch + return d.fatal("dependency file name too long for filesystem: {s}.d", .{base_name}); +} + fn getRandomFilename(d: *Driver, buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 { const random_bytes_count = 12; const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count); @@ -925,6 +1100,12 @@ fn processSource( var pp = try Preprocessor.initDefault(d.comp); defer pp.deinit(); + var name_buf: [std.fs.max_name_bytes]u8 = undefined; + var opt_dep_file = try d.initDepFile(source, &name_buf); + defer if (opt_dep_file) |*dep_file| dep_file.deinit(pp.gpa); + + if (opt_dep_file) |*dep_file| pp.dep_file = dep_file; + if (d.comp.langopts.ms_extensions) { d.comp.ms_cwd_source_id = source.id; } @@ -943,6 +1124,22 @@ fn processSource( try pp.preprocessSources(&.{ source, builtin, user_macros }); + var writer_buf: [4096]u8 = undefined; + if (opt_dep_file) |dep_file| { + const dep_file_name = try d.getDepFileName(source, writer_buf[0..std.fs.max_name_bytes]); + + const file = if (dep_file_name) |path| + d.comp.cwd.createFile(path, .{}) catch |er| + return d.fatal("unable to create dependency file '{s}': {s}", .{ path, errorDescription(er) }) + else + std.fs.File.stdout(); + defer if (dep_file_name != null) file.close(); + + var file_writer = file.writer(&writer_buf); + dep_file.write(&file_writer.interface) catch + return d.fatal("unable to write dependency file: {s}", .{errorDescription(file_writer.err.?)}); + } + if (d.only_preprocess) { d.printDiagnosticsStats(); @@ -951,6 +1148,11 @@ fn processSource( return; } + if (d.dependencies.m and !d.dependencies.md) { + if (fast_exit) std.process.exit(1); // Not linking, no need for cleanup. + return; + } + const file = if (d.output_name) |some| d.comp.cwd.createFile(some, .{}) catch |er| return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) }) @@ -997,7 +1199,6 @@ fn processSource( ); } - var name_buf: [std.fs.max_name_bytes]u8 = undefined; const out_file_name = try d.getOutFileName(source, &name_buf); if (d.use_assembly_backend) { @@ -1039,8 +1240,7 @@ fn processSource( defer ir.deinit(d.comp.gpa); if (d.verbose_ir) { - var stdout_buf: [4096]u8 = undefined; - var stdout = std.fs.File.stdout().writer(&stdout_buf); + var stdout = std.fs.File.stdout().writer(&writer_buf); ir.dump(d.comp.gpa, d.detectConfig(stdout.file), &stdout.interface) catch {}; } @@ -1065,8 +1265,7 @@ fn processSource( return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) }); defer out_file.close(); - var file_buf: [4096]u8 = undefined; - var file_writer = out_file.writer(&file_buf); + var file_writer = out_file.writer(&writer_buf); obj.finish(&file_writer.interface) catch return d.fatal("could not output to object file '{s}': {s}", .{ out_file_name, errorDescription(file_writer.err.?) }); } @@ -1236,7 +1435,7 @@ pub fn getPICMode(d: *Driver, lastpic: []const u8) Compilation.Error!struct { ba } else { pic, pie = .{ false, false }; if (target_util.isPS(target)) { - if (d.cmodel != .kernel) { + if (d.comp.cmodel != .kernel) { pic = true; try d.warn( "option '{s}' was ignored by the {s} toolchain, using '-fPIC'", diff --git a/lib/compiler/aro/aro/Parser.zig b/lib/compiler/aro/aro/Parser.zig index c8fc7decdb..e7a60eb76c 100644 --- a/lib/compiler/aro/aro/Parser.zig +++ b/lib/compiler/aro/aro/Parser.zig @@ -6904,6 +6904,9 @@ pub const Result = struct { try p.err(l_paren, .invalid_union_cast, .{res.qt}); return error.ParsingFailed; } + } else if (dest_qt.eql(res.qt, p.comp)) { + try p.err(l_paren, .cast_to_same_type, .{dest_qt}); + cast_kind = .no_op; } else { try p.err(l_paren, .invalid_cast_type, .{dest_qt}); return error.ParsingFailed; @@ -8720,7 +8723,9 @@ fn fieldAccess( }; if (record_ty.layout == null) { - std.debug.assert(is_ptr); + // Invalid use of incomplete type, error reported elsewhere. + if (!is_ptr) return error.ParsingFailed; + try p.err(field_name_tok - 2, .deref_incomplete_ty_ptr, .{expr_base_qt}); return error.ParsingFailed; } diff --git a/lib/compiler/aro/aro/Parser/Diagnostic.zig b/lib/compiler/aro/aro/Parser/Diagnostic.zig index a4c068c859..054979896d 100644 --- a/lib/compiler/aro/aro/Parser/Diagnostic.zig +++ b/lib/compiler/aro/aro/Parser/Diagnostic.zig @@ -694,6 +694,12 @@ pub const invalid_cast_type: Diagnostic = .{ .kind = .@"error", }; +pub const cast_to_same_type: Diagnostic = .{ + .fmt = "C99 forbids casting nonscalar type {qt} to the same type", + .kind = .off, + .extension = true, +}; + pub const invalid_cast_operand_type: Diagnostic = .{ .fmt = "operand of type {qt} where arithmetic or pointer type is required", .kind = .@"error", @@ -1484,9 +1490,10 @@ pub const duplicate_member: Diagnostic = .{ }; pub const binary_integer_literal: Diagnostic = .{ - .fmt = "binary integer literals are a GNU extension", + .fmt = "binary integer literals are a C23 extension", + .opt = .@"c23-extensions", .kind = .off, - .opt = .@"gnu-binary-literal", + .suppress_version = .c23, .extension = true, }; diff --git a/lib/compiler/aro/aro/Preprocessor.zig b/lib/compiler/aro/aro/Preprocessor.zig index e9317616eb..45d40af3c6 100644 --- a/lib/compiler/aro/aro/Preprocessor.zig +++ b/lib/compiler/aro/aro/Preprocessor.zig @@ -7,6 +7,7 @@ const Attribute = @import("Attribute.zig"); const Compilation = @import("Compilation.zig"); const Error = Compilation.Error; const Diagnostics = @import("Diagnostics.zig"); +const DepFile = @import("DepFile.zig"); const features = @import("features.zig"); const Hideset = @import("Hideset.zig"); const Parser = @import("Parser.zig"); @@ -157,6 +158,9 @@ hideset: Hideset, source_epoch: SourceEpoch, m_times: std.AutoHashMapUnmanaged(Source.Id, u64) = .{}, +/// The dependency file tracking all includes and embeds. +dep_file: ?*DepFile = null, + pub const parse = Parser.parse; pub const Linemarkers = enum { @@ -169,7 +173,7 @@ pub const Linemarkers = enum { }; pub fn init(comp: *Compilation, source_epoch: SourceEpoch) Preprocessor { - const pp = Preprocessor{ + const pp: Preprocessor = .{ .comp = comp, .diagnostics = comp.diagnostics, .gpa = comp.gpa, @@ -1614,13 +1618,18 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con else => unreachable, }; const filename = include_str[1 .. include_str.len - 1]; - if (builtin == .macro_param_has_include or pp.include_depth == 0) { - if (builtin == .macro_param_has_include_next) { - try pp.err(src_loc, .include_next_outside_header, .{}); + const res = res: { + if (builtin == .macro_param_has_include or pp.include_depth == 0) { + if (builtin == .macro_param_has_include_next) { + try pp.err(src_loc, .include_next_outside_header, .{}); + } + break :res try pp.comp.hasInclude(filename, src_loc.id, include_type, .first); } - return pp.comp.hasInclude(filename, src_loc.id, include_type, .first); - } - return pp.comp.hasInclude(filename, src_loc.id, include_type, .next); + break :res try pp.comp.hasInclude(filename, src_loc.id, include_type, .next); + }; + + if (res) if (pp.dep_file) |dep_file| try dep_file.addDependencyDupe(pp.gpa, pp.comp.arena, filename); + return res; }, else => unreachable, } @@ -1929,7 +1938,7 @@ fn expandFuncMacro( else => unreachable, }; const filename = include_str[1 .. include_str.len - 1]; - const contents = (try pp.comp.findEmbed(filename, arg[0].loc.id, include_type, .limited(1))) orelse + const contents = (try pp.comp.findEmbed(filename, arg[0].loc.id, include_type, .limited(1), pp.dep_file)) orelse break :res not_found; defer pp.comp.gpa.free(contents); @@ -2537,7 +2546,7 @@ fn expandedSliceExtra(pp: *const Preprocessor, tok: anytype, macro_ws_handling: if (tok.id.lexeme()) |some| { if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some; } - var tmp_tokenizer = Tokenizer{ + var tmp_tokenizer: Tokenizer = .{ .buf = pp.comp.getSource(tok.loc.id).buf, .langopts = pp.comp.langopts, .index = tok.loc.byte_offset, @@ -3087,7 +3096,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void { } } - const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit orelse .unlimited)) orelse + const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit orelse .unlimited, pp.dep_file)) orelse return pp.fatalNotFound(filename_tok, filename); defer pp.comp.gpa.free(embed_bytes); @@ -3143,6 +3152,7 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc if (pp.defines.contains(guard)) return; } + if (pp.dep_file) |dep| try dep.addDependency(pp.gpa, new_source.path); if (pp.verbose) { pp.verboseLog(first, "include file {s}", .{new_source.path}); } diff --git a/lib/compiler/aro/backend/CodeGenOptions.zig b/lib/compiler/aro/backend/CodeGenOptions.zig index afa5944890..304cc46951 100644 --- a/lib/compiler/aro/backend/CodeGenOptions.zig +++ b/lib/compiler/aro/backend/CodeGenOptions.zig @@ -11,7 +11,22 @@ pic_level: PicLevel, is_pie: bool, optimization_level: OptimizationLevel, /// Generate debug information -debug: bool, +debug: DebugFormat, +dwarf_version: DwarfVersion, + +pub const DebugFormat = union(enum) { + strip, + dwarf: std.dwarf.Format, + code_view, +}; + +pub const DwarfVersion = enum(u3) { + @"0" = 0, + @"2" = 2, + @"3" = 3, + @"4" = 4, + @"5" = 5, +}; pub const PicLevel = enum(u8) { /// Do not generate position-independent code @@ -60,5 +75,6 @@ pub const default: @This() = .{ .pic_level = .none, .is_pie = false, .optimization_level = .@"0", - .debug = false, + .debug = .strip, + .dwarf_version = .@"0", }; diff --git a/lib/compiler/aro/include/float.h b/lib/compiler/aro/include/float.h new file mode 100644 index 0000000000..f6fe454ab2 --- /dev/null +++ b/lib/compiler/aro/include/float.h @@ -0,0 +1,126 @@ +/* for the Aro C compiler */ + +#pragma once + +#undef FLT_RADIX +#define FLT_RADIX __FLT_RADIX__ + +#undef FLT_MANT_DIG +#define FLT_MANT_DIG __FLT_MANT_DIG__ + +#undef DBL_MANT_DIG +#define DBL_MANT_DIG __DBL_MANT_DIG__ + +#undef LDBL_MANT_DIG +#define LDBL_MANT_DIG __LDBL_MANT_DIG__ + +#if __STDC_VERSION__ >= 199901L +#undef FLT_EVAL_METHOD +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ + +#undef DECIMAL_DIG +#define DECIMAL_DIG __DECIMAL_DIG__ +#endif /* __STDC_VERSION__ >= 199901L */ + +#undef FLT_DIG +#define FLT_DIG __FLT_DIG__ + +#undef DBL_DIG +#define DBL_DIG __DBL_DIG__ + +#undef LDBL_DIG +#define LDBL_DIG __LDBL_DIG__ + +#undef FLT_MIN_EXP +#define FLT_MIN_EXP __FLT_MIN_EXP__ + +#undef DBL_MIN_EXP +#define DBL_MIN_EXP __DBL_MIN_EXP__ + +#undef LDBL_MIN_EXP +#define LDBL_MIN_EXP __LDBL_MIN_EXP__ + +#undef FLT_MIN_10_EXP +#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__ + +#undef DBL_MIN_10_EXP +#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__ + +#undef LDBL_MIN_10_EXP +#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ + +#undef FLT_MAX_EXP +#define FLT_MAX_EXP __FLT_MAX_EXP__ + +#undef DBL_MAX_EXP +#define DBL_MAX_EXP __DBL_MAX_EXP__ + +#undef LDBL_MAX_EXP +#define LDBL_MAX_EXP __LDBL_MAX_EXP__ + +#undef FLT_MAX_10_EXP +#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__ + +#undef DBL_MAX_10_EXP +#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__ + +#undef LDBL_MAX_10_EXP +#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ + +#undef FLT_MAX +#define FLT_MAX __FLT_MAX__ + +#undef DBL_MAX +#define DBL_MAX __DBL_MAX__ + +#undef LDBL_MAX +#define LDBL_MAX __LDBL_MAX__ + +#undef FLT_EPSILON +#define FLT_EPSILON __FLT_EPSILON__ + +#undef DBL_EPSILON +#define DBL_EPSILON __DBL_EPSILON__ + +#undef LDBL_EPSILON +#define LDBL_EPSILON __LDBL_EPSILON__ + +#undef FLT_MIN +#define FLT_MIN __FLT_MIN__ + +#undef DBL_MIN +#define DBL_MIN __DBL_MIN__ + +#undef LDBL_MIN +#define LDBL_MIN __LDBL_MIN__ + +#if __STDC_VERSION__ >= 201112L + +#undef FLT_TRUE_MIN +#define FLT_TRUE_MIN __FLT_DENORM_MIN__ + +#undef DBL_TRUE_MIN +#define DBL_TRUE_MIN __DBL_DENORM_MIN__ + +#undef LDBL_TRUE_MIN +#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__ + +#undef FLT_DECIMAL_DIG +#define FLT_DECIMAL_DIG __FLT_DECIMAL_DIG__ + +#undef DBL_DECIMAL_DIG +#define DBL_DECIMAL_DIG __DBL_DECIMAL_DIG__ + +#undef LDBL_DECIMAL_DIG +#define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__ + +#undef FLT_HAS_SUBNORM +#define FLT_HAS_SUBNORM __FLT_HAS_DENORM__ + +#undef DBL_HAS_SUBNORM +#define DBL_HAS_SUBNORM __DBL_HAS_DENORM__ + +#undef LDBL_HAS_SUBNORM +#define LDBL_HAS_SUBNORM __LDBL_HAS_DENORM__ + +#endif /* __STDC_VERSION__ >= 201112L */ diff --git a/lib/compiler/aro/include/iso646.h b/lib/compiler/aro/include/iso646.h new file mode 100644 index 0000000000..3e46910b8f --- /dev/null +++ b/lib/compiler/aro/include/iso646.h @@ -0,0 +1,15 @@ +/* for the Aro C compiler */ + +#pragma once + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= diff --git a/lib/compiler/aro/include/limits.h b/lib/compiler/aro/include/limits.h new file mode 100644 index 0000000000..4980bd7dbc --- /dev/null +++ b/lib/compiler/aro/include/limits.h @@ -0,0 +1,124 @@ +/* for the Aro C compiler */ + +#pragma once + +/* GlibC will try to include_next GCC's limits.h which will fail. + Define _GCC_LIMITS_H_ to prevent it. */ +#if defined __GNUC__ && !defined _GCC_LIMITS_H_ +#define _GCC_LIMITS_H_ +#endif + +/* Include the system's limits.h */ +#if __STDC_HOSTED__ && __has_include_next() +#include_next +#endif + +#undef SCHAR_MAX +#define SCHAR_MAX __SCHAR_MAX__ + +#undef SHRT_MAX +#define SHRT_MAX __SHRT_MAX__ + +#undef INT_MAX +#define INT_MAX __INT_MAX__ + +#undef LONG_MAX +#define LONG_MAX __LONG_MAX__ + +#undef SCHAR_MIN +#define SCHAR_MIN (-__SCHAR_MAX__-1) + +#undef SHRT_MIN +#define SHRT_MIN (-__SHRT_MAX__ -1) + +#undef INT_MIN +#define INT_MIN (-__INT_MAX__ -1) + +#undef LONG_MIN +#define LONG_MIN (-__LONG_MAX__ -1L) + +#undef UCHAR_MAX +#define UCHAR_MAX (__SCHAR_MAX__*2 +1) + +#undef USHRT_MAX +#define USHRT_MAX (__SHRT_MAX__ *2 +1) + +#undef UINT_MAX +#define UINT_MAX (__INT_MAX__ *2U +1U) + +#undef ULONG_MAX +#define ULONG_MAX (__LONG_MAX__ *2UL+1UL) + +#ifndef MB_LEN_MAX +#define MB_LEN_MAX 1 +#endif + +#undef CHAR_BIT +#define CHAR_BIT __CHAR_BIT__ + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L + +#undef BOOL_WIDTH +#define BOOL_WIDTH __BOOL_WIDTH__ + +#undef CHAR_WIDTH +#define CHAR_WIDTH CHAR_BIT + +#undef SCHAR_WIDTH +#define SCHAR_WIDTH CHAR_BIT + +#undef UCHAR_WIDTH +#define UCHAR_WIDTH CHAR_BIT + +#undef USHRT_WIDTH +#define USHRT_WIDTH __SHRT_WIDTH__ + +#undef SHRT_WIDTH +#define SHRT_WIDTH __SHRT_WIDTH__ + +#undef UINT_WIDTH +#define UINT_WIDTH __INT_WIDTH__ + +#undef INT_WIDTH +#define INT_WIDTH __INT_WIDTH__ + +#undef ULONG_WIDTH +#define ULONG_WIDTH __LONG_WIDTH__ + +#undef LONG_WIDTH +#define LONG_WIDTH __LONG_WIDTH__ + +#undef ULLONG_WIDTH +#define ULLONG_WIDTH __LLONG_WIDTH__ + +#undef LLONG_WIDTH +#define LLONG_WIDTH __LLONG_WIDTH__ + +#undef BITINT_MAXWIDTH +#define BITINT_MAXWIDTH __BITINT_MAXWIDTH__ + +#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L */ + +#undef CHAR_MIN +#undef CHAR_MAX +#ifdef __CHAR_UNSIGNED__ +#define CHAR_MIN 0 +#define CHAR_MAX UCHAR_MAX +#else +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX __SCHAR_MAX__ +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +#undef LLONG_MIN +#define LLONG_MIN (-__LONG_LONG_MAX__-1LL) + +#undef LLONG_MAX +#define LLONG_MAX __LONG_LONG_MAX__ + +#undef ULLONG_MAX +#define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL) + +#endif + diff --git a/lib/compiler/aro/include/stdalign.h b/lib/compiler/aro/include/stdalign.h new file mode 100644 index 0000000000..a836561619 --- /dev/null +++ b/lib/compiler/aro/include/stdalign.h @@ -0,0 +1,11 @@ +/* for the Aro C compiler */ + +#pragma once +#if __STDC_VERSION__ < 202311L + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 +#endif diff --git a/lib/compiler/aro/include/stdarg.h b/lib/compiler/aro/include/stdarg.h new file mode 100644 index 0000000000..49f7968ad8 --- /dev/null +++ b/lib/compiler/aro/include/stdarg.h @@ -0,0 +1,28 @@ +/* for the Aro C compiler */ + +#pragma once +/* Todo: Set to 202311L once header is compliant with C23 */ +#define __STDC_VERSION_STDARG_H__ 0 + +typedef __builtin_va_list va_list; +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L +/* C23 no longer requires the second parameter */ +#define va_start(ap, ...) __builtin_va_start(ap, __VA_ARGS__) +#else +#define va_start(ap, param) __builtin_va_start(ap, param) +#endif +#define va_end(ap) __builtin_va_end(ap) +#define va_arg(ap, type) __builtin_va_arg(ap, type) + +/* GCC and Clang always define __va_copy */ +#define __va_copy(d, s) __builtin_va_copy(d, s) + +/* but va_copy only on c99+ or when strict ansi mode is turned off */ +#if __STDC_VERSION__ >= 199901L || !defined(__STRICT_ANSI__) +#define va_copy(d, s) __builtin_va_copy(d, s) +#endif + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST 1 +typedef __builtin_va_list __gnuc_va_list; +#endif diff --git a/lib/compiler/aro/include/stdatomic.h b/lib/compiler/aro/include/stdatomic.h new file mode 100644 index 0000000000..19fe0fa8de --- /dev/null +++ b/lib/compiler/aro/include/stdatomic.h @@ -0,0 +1,138 @@ +/* for the Aro C compiler */ + +#pragma once + +#define __STDC_VERSION_STDATOMIC_H__ 202311L + +#if __STDC_HOSTED__ && __has_include_next() +#include_next +#else + +#include +#include + +#define ATOMIC_BOOL_LOCK_FREE __ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __ATOMIC_POINTER_LOCK_FREE +#if defined(__ATOMIC_CHAR8_T_LOCK_FREE) +#define ATOMIC_CHAR8_T_LOCK_FREE __ATOMIC_CHAR8_T_LOCK_FREE +#endif + +#if __STDC_VERSION__ < 202311L +/* ATOMIC_VAR_INIT was removed in C23 */ +#define ATOMIC_VAR_INIT(value) (value) +#endif + +#define atomic_init __c11_atomic_init + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +#define kill_dependency(y) (y) + +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) + +typedef _Atomic(_Bool) atomic_bool; +typedef _Atomic(char) atomic_char; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(short) atomic_short; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(int) atomic_int; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(long) atomic_long; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(uint_least16_t) atomic_char16_t; +typedef _Atomic(uint_least32_t) atomic_char32_t; +typedef _Atomic(wchar_t) atomic_wchar_t; +typedef _Atomic(int_least8_t) atomic_int_least8_t; +typedef _Atomic(uint_least8_t) atomic_uint_least8_t; +typedef _Atomic(int_least16_t) atomic_int_least16_t; +typedef _Atomic(uint_least16_t) atomic_uint_least16_t; +typedef _Atomic(int_least32_t) atomic_int_least32_t; +typedef _Atomic(uint_least32_t) atomic_uint_least32_t; +typedef _Atomic(int_least64_t) atomic_int_least64_t; +typedef _Atomic(uint_least64_t) atomic_uint_least64_t; +typedef _Atomic(int_fast8_t) atomic_int_fast8_t; +typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; +typedef _Atomic(int_fast16_t) atomic_int_fast16_t; +typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; +typedef _Atomic(int_fast32_t) atomic_int_fast32_t; +typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; +typedef _Atomic(int_fast64_t) atomic_int_fast64_t; +typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +typedef _Atomic(intmax_t) atomic_intmax_t; +typedef _Atomic(uintmax_t) atomic_uintmax_t; + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +typedef struct atomic_flag { atomic_bool _Value; } atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } + +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) + + +#endif diff --git a/lib/compiler/aro/include/stdbool.h b/lib/compiler/aro/include/stdbool.h new file mode 100644 index 0000000000..58ce2b1244 --- /dev/null +++ b/lib/compiler/aro/include/stdbool.h @@ -0,0 +1,13 @@ +/* for the Aro C compiler */ + +#pragma once + +#if __STDC_VERSION__ < 202311L +#define bool _Bool + +#define true 1 +#define false 0 + +#define __bool_true_false_are_defined 1 + +#endif diff --git a/lib/compiler/aro/include/stdckdint.h b/lib/compiler/aro/include/stdckdint.h new file mode 100644 index 0000000000..44d954cf93 --- /dev/null +++ b/lib/compiler/aro/include/stdckdint.h @@ -0,0 +1,9 @@ +/* for the Aro C compiler */ + +#pragma once + +#define __STDC_VERSION_STDCKDINT_H__ 202311L + +#define ckd_add(result, a, b) __builtin_add_overflow(a, b, result) +#define ckd_sub(result, a, b) __builtin_sub_overflow(a, b, result) +#define ckd_mul(result, a, b) __builtin_mul_overflow(a, b, result) diff --git a/lib/compiler/aro/include/stddef.h b/lib/compiler/aro/include/stddef.h new file mode 100644 index 0000000000..bda4c94297 --- /dev/null +++ b/lib/compiler/aro/include/stddef.h @@ -0,0 +1,31 @@ +/* for the Aro C compiler */ + +#pragma once + +#define __STDC_VERSION_STDDEF_H__ 202311L + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __SIZE_TYPE__ size_t; +typedef __WCHAR_TYPE__ wchar_t; + +/* define max_align_t to match GCC and Clang */ +typedef struct { + long long __aro_max_align_ll; + long double __aro_max_align_ld; +} max_align_t; + +#define NULL ((void*)0) +#define offsetof(T, member) __builtin_offsetof(T, member) + +#if __STDC_VERSION__ >= 202311L +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpre-c23-compat" + typedef typeof(nullptr) nullptr_t; +# pragma GCC diagnostic pop + +# if defined unreachable +# error unreachable() is a standard macro in C23 +# else +# define unreachable() __builtin_unreachable() +# endif +#endif diff --git a/lib/compiler/aro/include/stdint.h b/lib/compiler/aro/include/stdint.h new file mode 100644 index 0000000000..2e1929097d --- /dev/null +++ b/lib/compiler/aro/include/stdint.h @@ -0,0 +1,289 @@ +/* for the Aro C compiler */ + +#pragma once + + +#if __STDC_HOSTED__ && __has_include_next() + +# include_next + +#else + +#define __stdint_int_c_cat(X, Y) X ## Y +#define __stdint_int_c(V, SUFFIX) __stdint_int_c_cat(V, SUFFIX) +#define __stdint_uint_c(V, SUFFIX) __stdint_int_c_cat(V##U, SUFFIX) + +#define INTPTR_MIN (-__INTPTR_MAX__-1) +#define INTPTR_MAX __INTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1) +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#define INTMAX_MIN (-__INTMAX_MAX__-1) +#define INTMAX_MAX __INTMAX_MAX__ +#define UINTMAX_MAX __UINTMAX_MAX__ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define INTPTR_WIDTH __INTPTR_WIDTH__ +# define UINTPTR_WIDTH __UINTPTR_WIDTH__ +# define INTMAX_WIDTH __INTMAX_WIDTH__ +# define UINTMAX_WIDTH __UINTMAX_WIDTH__ +# define PTRDIFF_WIDTH __PTRDIFF_WIDTH__ +# define SIZE_WIDTH __SIZE_WIDTH__ +# define WCHAR_WIDTH __WCHAR_WIDTH__ +#endif + +typedef __INTMAX_TYPE__ intmax_t; +typedef __UINTMAX_TYPE__ uintmax_t; + +#ifndef _INTPTR_T +# ifndef __intptr_t_defined + typedef __INTPTR_TYPE__ intptr_t; +# define __intptr_t_defined +# define _INTPTR_T +# endif +#endif + +#ifndef _UINTPTR_T + typedef __UINTPTR_TYPE__ uintptr_t; +# define _UINTPTR_T +#endif + + +#ifdef __INT64_TYPE__ +# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/ + typedef __INT64_TYPE__ int64_t; +# endif /* __int8_t_defined */ + typedef __UINT64_TYPE__ uint64_t; + +# undef __int64_c_suffix +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# ifdef __INT64_C_SUFFIX__ +# define __int64_c_suffix __INT64_C_SUFFIX__ +# define __int32_c_suffix __INT64_C_SUFFIX__ +# define __int16_c_suffix __INT64_C_SUFFIX__ +# define __int8_c_suffix __INT64_C_SUFFIX__ +# endif /* __INT64_C_SUFFIX__ */ + +# ifdef __int64_c_suffix +# define INT64_C(v) (__stdint_int_c(v, __int64_c_suffix)) +# define UINT64_C(v) (__stdint_uint_c(v, __int64_c_suffix)) +# else +# define INT64_C(v) (v) +# define UINT64_C(v) (v ## U) +# endif /* __int64_c_suffix */ + +# define INT64_MAX INT64_C( 9223372036854775807) +# define INT64_MIN (-INT64_C( 9223372036854775807)-1) +# define UINT64_MAX UINT64_C(18446744073709551615) +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define UINT64_WIDTH 64 +# define INT64_WIDTH UINT64_WIDTH +# endif /* __STDC_VERSION__ */ + +#endif /* __INT64_TYPE__ */ + +#ifdef __INT32_TYPE__ +# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/ + typedef __INT32_TYPE__ int32_t; +# endif /* __int8_t_defined */ + typedef __UINT32_TYPE__ uint32_t; + +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# ifdef __INT32_C_SUFFIX__ +# define __int32_c_suffix __INT32_C_SUFFIX__ +# define __int16_c_suffix __INT32_C_SUFFIX__ +# define __int8_c_suffix __INT32_C_SUFFIX__ +# endif /* __INT32_C_SUFFIX__ */ + +# ifdef __int32_c_suffix +# define INT32_C(v) (__stdint_int_c(v, __int32_c_suffix)) +# define UINT32_C(v) (__stdint_uint_c(v, __int32_c_suffix)) +# else +# define INT32_C(v) (v) +# define UINT32_C(v) (v ## U) +# endif /* __int32_c_suffix */ + +# define INT32_MAX INT32_C( 2147483647) +# define INT32_MIN (-INT32_C( 2147483647)-1) +# define UINT32_MAX UINT32_C(4294967295) +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define UINT32_WIDTH 32 +# define INT32_WIDTH UINT32_WIDTH +# endif /* __STDC_VERSION__ */ + +#endif /* __INT32_TYPE__ */ + +#ifdef __INT16_TYPE__ +# ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/ + typedef __INT16_TYPE__ int16_t; +# endif /* __int8_t_defined */ + typedef __UINT16_TYPE__ uint16_t; + +# undef __int16_c_suffix +# undef __int8_c_suffix +# ifdef __INT16_C_SUFFIX__ +# define __int16_c_suffix __INT16_C_SUFFIX__ +# define __int8_c_suffix __INT16_C_SUFFIX__ +# endif /* __INT16_C_SUFFIX__ */ + +# ifdef __int16_c_suffix +# define INT16_C(v) (__stdint_int_c(v, __int16_c_suffix)) +# define UINT16_C(v) (__stdint_uint_c(v, __int16_c_suffix)) +# else +# define INT16_C(v) (v) +# define UINT16_C(v) (v ## U) +# endif /* __int16_c_suffix */ + +# define INT16_MAX INT16_C( 32767) +# define INT16_MIN (-INT16_C( 32767)-1) +# define UINT16_MAX UINT16_C(65535) +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define UINT16_WIDTH 16 +# define INT16_WIDTH UINT16_WIDTH +# endif /* __STDC_VERSION__ */ + +#endif /* __INT16_TYPE__ */ + +#ifdef __INT8_TYPE__ +# ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/ + typedef __INT8_TYPE__ int8_t; +# endif /* __int8_t_defined */ + typedef __UINT8_TYPE__ uint8_t; + +# undef __int8_c_suffix +# ifdef __INT8_C_SUFFIX__ +# define __int8_c_suffix __INT8_C_SUFFIX__ +# endif /* __INT8_C_SUFFIX__ */ + +# ifdef __int8_c_suffix +# define INT8_C(v) (__stdint_int_c(v, __int8_c_suffix)) +# define UINT8_C(v) (__stdint_uint_c(v, __int8_c_suffix)) +# else +# define INT8_C(v) (v) +# define UINT8_C(v) (v ## U) +# endif /* __int8_c_suffix */ + +# define INT8_MAX INT8_C(127) +# define INT8_MIN (-INT8_C(127)-1) +# define UINT8_MAX UINT8_C(255) +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define UINT8_WIDTH 8 +# define INT8_WIDTH UINT8_WIDTH +# endif /* __STDC_VERSION__ */ + +#endif /* __INT8_TYPE__ */ + +typedef __INT_LEAST64_TYPE__ int_least64_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST8_TYPE__ int_least8_t; + +typedef __UINT_LEAST64_TYPE__ uint_least64_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST8_TYPE__ uint_least8_t; + +#define INT_LEAST8_MAX __INT_LEAST8_MAX__ +#define INT_LEAST8_MIN (-__INT_LEAST8_MAX__-1) +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ + +#define INT_LEAST16_MAX __INT_LEAST16_MAX__ +#define INT_LEAST16_MIN (-__INT_LEAST16_MAX__-1) +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ + +#define INT_LEAST32_MAX __INT_LEAST32_MAX__ +#define INT_LEAST32_MIN (-__INT_LEAST32_MAX__-1) +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ + +#define INT_LEAST64_MAX __INT_LEAST64_MAX__ +#define INT_LEAST64_MIN (-__INT_LEAST64_MAX__-1) +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ + + +typedef __INT_FAST64_TYPE__ int_fast64_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST8_TYPE__ int_fast8_t; + +typedef __UINT_FAST64_TYPE__ uint_fast64_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST8_TYPE__ uint_fast8_t; + +#define INT_FAST8_MAX __INT_FAST8_MAX__ +#define INT_FAST8_MIN (-__INT_FAST8_MAX__-1) +#define UINT_FAST8_MAX __UINT_FAST8_MAX__ + +#define INT_FAST16_MAX __INT_FAST16_MAX__ +#define INT_FAST16_MIN (-__INT_FAST16_MAX__-1) +#define UINT_FAST16_MAX __UINT_FAST16_MAX__ + +#define INT_FAST32_MAX __INT_FAST32_MAX__ +#define INT_FAST32_MIN (-__INT_FAST32_MAX__-1) +#define UINT_FAST32_MAX __UINT_FAST32_MAX__ + +#define INT_FAST64_MAX __INT_FAST64_MAX__ +#define INT_FAST64_MIN (-__INT_FAST64_MAX__-1) +#define UINT_FAST64_MAX __UINT_FAST64_MAX__ + + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L + +#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__ +#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__ +#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__ +#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__ + +#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__ +#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__ +#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__ +#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__ + +#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__ +#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__ +#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__ +#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__ + +#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__ +#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__ +#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__ +#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__ + +#endif + +#ifdef __SIZEOF_INT128__ +typedef signed __int128 int128_t; +typedef unsigned __int128 uint128_t; +typedef signed __int128 int_fast128_t; +typedef unsigned __int128 uint_fast128_t; +typedef signed __int128 int_least128_t; +typedef unsigned __int128 uint_least128_t; +# define UINT128_MAX ((uint128_t)-1) +# define INT128_MAX ((int128_t)+(UINT128_MAX/2)) +# define INT128_MIN (-INT128_MAX-1) +# define UINT_LEAST128_MAX UINT128_MAX +# define INT_LEAST128_MAX INT128_MAX +# define INT_LEAST128_MIN INT128_MIN +# define UINT_FAST128_MAX UINT128_MAX +# define INT_FAST128_MAX INT128_MAX +# define INT_FAST128_MIN INT128_MIN +# define INT128_WIDTH 128 +# define UINT128_WIDTH 128 +# define INT_LEAST128_WIDTH 128 +# define UINT_LEAST128_WIDTH 128 +# define INT_FAST128_WIDTH 128 +# define UINT_FAST128_WIDTH 128 +# if UINT128_WIDTH > __LLONG_WIDTH__ +# define INT128_C(N) ((int_least128_t)+N ## WB) +# define UINT128_C(N) ((uint_least128_t)+N ## WBU) +# else +# define INT128_C(N) ((int_least128_t)+N ## LL) +# define UINT128_C(N) ((uint_least128_t)+N ## LLU) +# endif +#endif + +#endif /* __STDC_HOSTED__ && __has_include_next() */ diff --git a/lib/compiler/aro/include/stdnoreturn.h b/lib/compiler/aro/include/stdnoreturn.h new file mode 100644 index 0000000000..200789f547 --- /dev/null +++ b/lib/compiler/aro/include/stdnoreturn.h @@ -0,0 +1,6 @@ +/* for the Aro C compiler */ + +#pragma once + +#define noreturn _Noreturn +#define __noreturn_is_defined 1 diff --git a/lib/compiler/aro/include/varargs.h b/lib/compiler/aro/include/varargs.h new file mode 100644 index 0000000000..c6a6db41b8 --- /dev/null +++ b/lib/compiler/aro/include/varargs.h @@ -0,0 +1,3 @@ +/* for the Aro C compiler */ +#pragma once +#error please use instead of diff --git a/lib/compiler/translate-c/Translator.zig b/lib/compiler/translate-c/Translator.zig index f5dea2f430..e31eb2e574 100644 --- a/lib/compiler/translate-c/Translator.zig +++ b/lib/compiler/translate-c/Translator.zig @@ -171,7 +171,7 @@ pub const Options = struct { tree: *const aro.Tree, }; -pub fn translate(options: Options) ![]u8 { +pub fn translate(options: Options) mem.Allocator.Error![]u8 { const gpa = options.gpa; var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); @@ -219,19 +219,19 @@ pub fn translate(options: Options) ![]u8 { var aw: std.Io.Writer.Allocating = .init(gpa); defer aw.deinit(); - try aw.writer.writeAll( + aw.writer.writeAll( \\pub const __builtin = @import("std").zig.c_translation.builtins; \\pub const __helpers = @import("std").zig.c_translation.helpers; \\ \\ - ); + ) catch return error.OutOfMemory; var zig_ast = try ast.render(gpa, translator.global_scope.nodes.items); defer { gpa.free(zig_ast.source); zig_ast.deinit(gpa); } - try zig_ast.render(gpa, &aw.writer, .{}); + zig_ast.render(gpa, &aw.writer, .{}) catch return error.OutOfMemory; return aw.toOwnedSlice(); } diff --git a/lib/compiler/translate-c/main.zig b/lib/compiler/translate-c/main.zig index 4d90433239..685984b985 100644 --- a/lib/compiler/translate-c/main.zig +++ b/lib/compiler/translate-c/main.zig @@ -109,8 +109,6 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void { var macro_buf: std.ArrayListUnmanaged(u8) = .empty; defer macro_buf.deinit(gpa); - try macro_buf.appendSlice(gpa, "#define __TRANSLATE_C__ 1\n"); - var discard_buf: [256]u8 = undefined; var discarding: std.io.Writer.Discarding = .init(&discard_buf); assert(!try d.parseArgs(&discarding.writer, ¯o_buf, aro_args)); @@ -146,6 +144,12 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void { var pp = try aro.Preprocessor.initDefault(d.comp); defer pp.deinit(); + var name_buf: [std.fs.max_name_bytes]u8 = undefined; + var opt_dep_file = try d.initDepFile(source, &name_buf); + defer if (opt_dep_file) |*dep_file| dep_file.deinit(pp.gpa); + + if (opt_dep_file) |*dep_file| pp.dep_file = dep_file; + try pp.preprocessSources(&.{ source, builtin_macros, user_macros }); var c_tree = try pp.parse(); @@ -156,6 +160,22 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void { return error.FatalError; } + var out_buf: [4096]u8 = undefined; + if (opt_dep_file) |dep_file| { + const dep_file_name = try d.getDepFileName(source, out_buf[0..std.fs.max_name_bytes]); + + const file = if (dep_file_name) |path| + d.comp.cwd.createFile(path, .{}) catch |er| + return d.fatal("unable to create dependency file '{s}': {s}", .{ path, aro.Driver.errorDescription(er) }) + else + std.fs.File.stdout(); + defer if (dep_file_name != null) file.close(); + + var file_writer = file.writer(&out_buf); + dep_file.write(&file_writer.interface) catch + return d.fatal("unable to write dependency file: {s}", .{aro.Driver.errorDescription(file_writer.err.?)}); + } + const rendered_zig = try Translator.translate(.{ .gpa = gpa, .comp = d.comp, @@ -182,7 +202,6 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void { out_file_path = path; } - var out_buf: [4096]u8 = undefined; var out_writer = out_file.writer(&out_buf); out_writer.interface.writeAll(rendered_zig) catch return d.fatal("failed to write result to '{s}': {s}", .{ out_file_path, aro.Driver.errorDescription(out_writer.err.?) }); diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 18b3a33992..2404233367 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -333,7 +333,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { defer std.debug.unlockStderrWriter(); for (aro_comp.diagnostics.output.to_list.messages.items) |msg| { if (msg.kind == .@"fatal error" or msg.kind == .@"error") { - aro.Diagnostics.writeToWriter(msg, w, std.io.tty.detectConfig(std.fs.File.stderr())) catch {}; + msg.write(w, .detect(std.fs.File.stderr()), true) catch {}; return error.AroPreprocessorFailed; } }