diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 800a16f660..b949f92feb 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -2693,7 +2693,10 @@ pub const MEM_RESERVE_PLACEHOLDERS = 0x2; pub const MEM_DECOMMIT = 0x4000; pub const MEM_RELEASE = 0x8000; -pub const PTHREAD_START_ROUTINE = fn (LPVOID) callconv(.C) DWORD; +pub const PTHREAD_START_ROUTINE = switch (builtin.zig_backend) { + .stage1 => fn (LPVOID) callconv(.C) DWORD, + else => *const fn (LPVOID) callconv(.C) DWORD, +}; pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; pub const WIN32_FIND_DATAW = extern struct { @@ -2866,7 +2869,10 @@ pub const IMAGE_TLS_DIRECTORY = extern struct { pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; -pub const PIMAGE_TLS_CALLBACK = ?fn (PVOID, DWORD, PVOID) callconv(.C) void; +pub const PIMAGE_TLS_CALLBACK = switch (builtin.zig_backend) { + .stage1 => ?fn (PVOID, DWORD, PVOID) callconv(.C) void, + else => ?*const fn (PVOID, DWORD, PVOID) callconv(.C) void, +}; pub const PROV_RSA_FULL = 1; @@ -2892,7 +2898,10 @@ pub const FILE_ACTION_MODIFIED = 0x00000003; pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; -pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?fn (DWORD, DWORD, *OVERLAPPED) callconv(.C) void; +pub const LPOVERLAPPED_COMPLETION_ROUTINE = switch (builtin.zig_backend) { + .stage1 => ?fn (DWORD, DWORD, *OVERLAPPED) callconv(.C) void, + else => ?*const fn (DWORD, DWORD, *OVERLAPPED) callconv(.C) void, +}; pub const FILE_NOTIFY_CHANGE_CREATION = 64; pub const FILE_NOTIFY_CHANGE_SIZE = 8; @@ -2945,7 +2954,10 @@ pub const RTL_CRITICAL_SECTION = extern struct { pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; pub const INIT_ONCE = RTL_RUN_ONCE; pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; -pub const INIT_ONCE_FN = fn (InitOnce: *INIT_ONCE, Parameter: ?*anyopaque, Context: ?*anyopaque) callconv(.C) BOOL; +pub const INIT_ONCE_FN = switch (builtin.zig_backend) { + .stage1 => fn (InitOnce: *INIT_ONCE, Parameter: ?*anyopaque, Context: ?*anyopaque) callconv(.C) BOOL, + else => *const fn (InitOnce: *INIT_ONCE, Parameter: ?*anyopaque, Context: ?*anyopaque) callconv(.C) BOOL, +}; pub const RTL_RUN_ONCE = extern struct { Ptr: ?*anyopaque, @@ -3230,7 +3242,10 @@ pub const EXCEPTION_POINTERS = extern struct { ContextRecord: *std.os.windows.CONTEXT, }; -pub const VECTORED_EXCEPTION_HANDLER = fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long; +pub const VECTORED_EXCEPTION_HANDLER = switch (builtin.zig_backend) { + .stage1 => fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long, + else => *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long, +}; pub const OBJECT_ATTRIBUTES = extern struct { Length: ULONG, @@ -3506,7 +3521,10 @@ pub const RTL_DRIVE_LETTER_CURDIR = extern struct { DosPath: UNICODE_STRING, }; -pub const PPS_POST_PROCESS_INIT_ROUTINE = ?fn () callconv(.C) void; +pub const PPS_POST_PROCESS_INIT_ROUTINE = switch (builtin.zig_backend) { + .stage1 => ?fn () callconv(.C) void, + else => ?*const fn () callconv(.C) void, +}; pub const FILE_BOTH_DIR_INFORMATION = extern struct { NextEntryOffset: ULONG, @@ -3526,7 +3544,10 @@ pub const FILE_BOTH_DIR_INFORMATION = extern struct { }; pub const FILE_BOTH_DIRECTORY_INFORMATION = FILE_BOTH_DIR_INFORMATION; -pub const IO_APC_ROUTINE = fn (PVOID, *IO_STATUS_BLOCK, ULONG) callconv(.C) void; +pub const IO_APC_ROUTINE = switch (builtin.zig_backend) { + .stage1 => fn (PVOID, *IO_STATUS_BLOCK, ULONG) callconv(.C) void, + else => *const fn (PVOID, *IO_STATUS_BLOCK, ULONG) callconv(.C) void, +}; pub const CURDIR = extern struct { DosPath: UNICODE_STRING, @@ -3598,8 +3619,14 @@ pub const ENUM_PAGE_FILE_INFORMATION = extern struct { PeakUsage: SIZE_T, }; -pub const PENUM_PAGE_FILE_CALLBACKW = ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.C) BOOL; -pub const PENUM_PAGE_FILE_CALLBACKA = ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.C) BOOL; +pub const PENUM_PAGE_FILE_CALLBACKW = switch (builtin.zig_backend) { + .stage1 => ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.C) BOOL, + else => ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.C) BOOL, +}; +pub const PENUM_PAGE_FILE_CALLBACKA = switch (builtin.zig_backend) { + .stage1 => ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.C) BOOL, + else => ?*const fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.C) BOOL, +}; pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct { BasicInfo: PSAPI_WS_WATCH_INFORMATION, @@ -3699,4 +3726,7 @@ pub const CTRL_CLOSE_EVENT: DWORD = 2; pub const CTRL_LOGOFF_EVENT: DWORD = 5; pub const CTRL_SHUTDOWN_EVENT: DWORD = 6; -pub const HANDLER_ROUTINE = fn (dwCtrlType: DWORD) callconv(.C) BOOL; +pub const HANDLER_ROUTINE = switch (builtin.zig_backend) { + .stage1 => fn (dwCtrlType: DWORD) callconv(.C) BOOL, + else => *const fn (dwCtrlType: DWORD) callconv(.C) BOOL, +}; diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index 46078d6252..a44296c920 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -14,7 +14,7 @@ const ArrayList = std.ArrayList; // documentation and/or contributors. // https://llvm.org/docs/PDB/DbiStream.html#stream-header -pub const DbiStreamHeader = packed struct { +pub const DbiStreamHeader = extern struct { VersionSignature: i32, VersionHeader: u32, Age: u32, @@ -37,7 +37,7 @@ pub const DbiStreamHeader = packed struct { Padding: u32, }; -pub const SectionContribEntry = packed struct { +pub const SectionContribEntry = extern struct { /// COFF Section index, 1-based Section: u16, Padding1: [2]u8, @@ -50,7 +50,7 @@ pub const SectionContribEntry = packed struct { RelocCrc: u32, }; -pub const ModInfo = packed struct { +pub const ModInfo = extern struct { Unused1: u32, SectionContr: SectionContribEntry, Flags: u16, @@ -68,7 +68,7 @@ pub const ModInfo = packed struct { //ObjFileName: char[], }; -pub const SectionMapHeader = packed struct { +pub const SectionMapHeader = extern struct { /// Number of segment descriptors Count: u16, @@ -76,7 +76,7 @@ pub const SectionMapHeader = packed struct { LogCount: u16, }; -pub const SectionMapEntry = packed struct { +pub const SectionMapEntry = extern struct { /// See the SectionMapEntryFlags enum below. Flags: u16, @@ -310,7 +310,7 @@ pub const SymbolKind = enum(u16) { pub const TypeIndex = u32; -pub const ProcSym = packed struct { +pub const ProcSym = extern struct { Parent: u32, End: u32, Next: u32, @@ -342,7 +342,7 @@ pub const SectionContrSubstreamVersion = enum(u32) { _, }; -pub const RecordPrefix = packed struct { +pub const RecordPrefix = extern struct { /// Record length, starting from &RecordKind. RecordLen: u16, @@ -354,7 +354,7 @@ pub const RecordPrefix = packed struct { /// The structure definition follows. /// LineBlockFragmentHeader Blocks[] /// Each `LineBlockFragmentHeader` as specified below. -pub const LineFragmentHeader = packed struct { +pub const LineFragmentHeader = extern struct { /// Code offset of line contribution. RelocOffset: u32, @@ -376,7 +376,7 @@ pub const LineFlags = packed struct { /// header. The structure definitions follow. /// LineNumberEntry Lines[NumLines]; /// ColumnNumberEntry Columns[NumLines]; -pub const LineBlockFragmentHeader = packed struct { +pub const LineBlockFragmentHeader = extern struct { /// Offset of FileChecksum entry in File /// checksums buffer. The checksum entry then /// contains another offset into the string @@ -388,7 +388,7 @@ pub const LineBlockFragmentHeader = packed struct { BlockSize: u32, }; -pub const LineNumberEntry = packed struct { +pub const LineNumberEntry = extern struct { /// Offset to start of code bytes for line number Offset: u32, Flags: u32, @@ -404,13 +404,13 @@ pub const LineNumberEntry = packed struct { }; }; -pub const ColumnNumberEntry = packed struct { +pub const ColumnNumberEntry = extern struct { StartColumn: u16, EndColumn: u16, }; /// Checksum bytes follow. -pub const FileChecksumEntryHeader = packed struct { +pub const FileChecksumEntryHeader = extern struct { /// Byte offset of filename in global string table. FileNameOffset: u32, @@ -441,7 +441,7 @@ pub const DebugSubsectionKind = enum(u32) { CoffSymbolRVA = 0xfd, }; -pub const DebugSubsectionHeader = packed struct { +pub const DebugSubsectionHeader = extern struct { /// codeview::DebugSubsectionKind enum Kind: DebugSubsectionKind, @@ -449,7 +449,7 @@ pub const DebugSubsectionHeader = packed struct { Length: u32, }; -pub const PDBStringTableHeader = packed struct { +pub const PDBStringTableHeader = extern struct { /// PDBStringTableSignature Signature: u32, @@ -686,12 +686,12 @@ pub const Pdb = struct { var symbol_i: usize = 0; while (symbol_i != module.symbols.len) { - const prefix = @ptrCast(*RecordPrefix, &module.symbols[symbol_i]); + const prefix = @ptrCast(*align(1) RecordPrefix, &module.symbols[symbol_i]); if (prefix.RecordLen < 2) return null; switch (prefix.RecordKind) { .S_LPROC32, .S_GPROC32 => { - const proc_sym = @ptrCast(*ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]); + const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]); if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) { return mem.sliceTo(@ptrCast([*:0]u8, proc_sym) + @sizeOf(ProcSym), 0); } @@ -712,7 +712,7 @@ pub const Pdb = struct { var skip_len: usize = undefined; const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { - const subsect_hdr = @ptrCast(*DebugSubsectionHeader, &subsect_info[sect_offset]); + const subsect_hdr = @ptrCast(*align(1) DebugSubsectionHeader, &subsect_info[sect_offset]); skip_len = subsect_hdr.Length; sect_offset += @sizeOf(DebugSubsectionHeader); @@ -720,7 +720,7 @@ pub const Pdb = struct { .Lines => { var line_index = sect_offset; - const line_hdr = @ptrCast(*LineFragmentHeader, &subsect_info[line_index]); + const line_hdr = @ptrCast(*align(1) LineFragmentHeader, &subsect_info[line_index]); if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo; line_index += @sizeOf(LineFragmentHeader); @@ -734,7 +734,7 @@ pub const Pdb = struct { const subsection_end_index = sect_offset + subsect_hdr.Length; while (line_index < subsection_end_index) { - const block_hdr = @ptrCast(*LineBlockFragmentHeader, &subsect_info[line_index]); + const block_hdr = @ptrCast(*align(1) LineBlockFragmentHeader, &subsect_info[line_index]); line_index += @sizeOf(LineBlockFragmentHeader); const start_line_index = line_index; @@ -746,7 +746,7 @@ pub const Pdb = struct { // This is done with a simple linear search. var line_i: u32 = 0; while (line_i < block_hdr.NumLines) : (line_i += 1) { - const line_num_entry = @ptrCast(*LineNumberEntry, &subsect_info[line_index]); + const line_num_entry = @ptrCast(*align(1) LineNumberEntry, &subsect_info[line_index]); line_index += @sizeOf(LineNumberEntry); const vaddr_start = frag_vaddr_start + line_num_entry.Offset; @@ -758,7 +758,7 @@ pub const Pdb = struct { // line_i == 0 would mean that no matching LineNumberEntry was found. if (line_i > 0) { const subsect_index = checksum_offset + block_hdr.NameIndex; - const chksum_hdr = @ptrCast(*FileChecksumEntryHeader, &module.subsect_info[subsect_index]); + const chksum_hdr = @ptrCast(*align(1) FileChecksumEntryHeader, &module.subsect_info[subsect_index]); const strtab_offset = @sizeOf(PDBStringTableHeader) + chksum_hdr.FileNameOffset; try self.string_table.?.seekTo(strtab_offset); const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024); @@ -768,12 +768,12 @@ pub const Pdb = struct { const column = if (has_column) blk: { const start_col_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines; const col_index = start_col_index + @sizeOf(ColumnNumberEntry) * line_entry_idx; - const col_num_entry = @ptrCast(*ColumnNumberEntry, &subsect_info[col_index]); + const col_num_entry = @ptrCast(*align(1) ColumnNumberEntry, &subsect_info[col_index]); break :blk col_num_entry.StartColumn; } else 0; const found_line_index = start_line_index + line_entry_idx * @sizeOf(LineNumberEntry); - const line_num_entry = @ptrCast(*LineNumberEntry, &subsect_info[found_line_index]); + const line_num_entry = @ptrCast(*align(1) LineNumberEntry, &subsect_info[found_line_index]); const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags); return debug.LineInfo{ @@ -833,7 +833,7 @@ pub const Pdb = struct { var sect_offset: usize = 0; var skip_len: usize = undefined; while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) { - const subsect_hdr = @ptrCast(*DebugSubsectionHeader, &mod.subsect_info[sect_offset]); + const subsect_hdr = @ptrCast(*align(1) DebugSubsectionHeader, &mod.subsect_info[sect_offset]); skip_len = subsect_hdr.Length; sect_offset += @sizeOf(DebugSubsectionHeader); @@ -969,7 +969,7 @@ fn blockCountFromSize(size: u32, block_size: u32) u32 { } // https://llvm.org/docs/PDB/MsfFile.html#the-superblock -const SuperBlock = packed struct { +const SuperBlock = extern struct { /// The LLVM docs list a space between C / C++ but empirically this is not the case. const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00"; diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index d71f2b9274..4b6c80ac66 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -28,7 +28,7 @@ pub fn main() void { { return main2() catch @panic("test failure"); } - if (builtin.zig_backend == .stage1) processArgs(); + processArgs(); const test_fn_list = builtin.test_functions; var ok_count: usize = 0; var skip_count: usize = 0; diff --git a/lib/std/start.zig b/lib/std/start.zig index 5690337317..81c7942bc1 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -29,9 +29,7 @@ comptime { builtin.zig_backend == .stage2_aarch64 or builtin.zig_backend == .stage2_arm or builtin.zig_backend == .stage2_riscv64 or - builtin.zig_backend == .stage2_sparcv9 or - (builtin.zig_backend == .stage2_llvm and native_os != .linux and native_os != .macos) or - (builtin.zig_backend == .stage2_llvm and native_arch != .x86_64 and native_arch != .aarch64)) + builtin.zig_backend == .stage2_sparcv9) { if (builtin.output_mode == .Exe) { if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) { diff --git a/src/Air.zig b/src/Air.zig index 0968d95180..2dae8454cf 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -815,6 +815,8 @@ pub const VectorCmp = struct { /// 1. `Inst.Ref` for every inputs_len /// 2. for every outputs_len /// - constraint: memory at this position is reinterpreted as a null +/// terminated string. +/// - name: memory at this position is reinterpreted as a null /// terminated string. pad to the next u32 after the null byte. /// 3. for every inputs_len /// - constraint: memory at this position is reinterpreted as a null diff --git a/src/Sema.zig b/src/Sema.zig index 87cb7cc9d2..d9c2d1cc2a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4323,7 +4323,7 @@ pub fn analyzeExport( const exported_decl = mod.declPtr(exported_decl_index); // TODO run the same checks as we do for C ABI struct fields switch (exported_decl.ty.zigTypeTag()) { - .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float => {}, + .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float, .Pointer, .Optional => {}, else => return sema.fail(block, src, "unable to export type '{}'", .{ exported_decl.ty.fmt(sema.mod), }), @@ -10535,7 +10535,11 @@ fn zirAsm( var output_type_bits = extra.data.output_type_bits; var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len; - const Output = struct { constraint: []const u8, ty: Type }; + const Output = struct { + constraint: []const u8, + name: []const u8, + ty: Type, + }; const output: ?Output = if (outputs_len == 0) null else blk: { const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); extra_i = output.end; @@ -10548,10 +10552,12 @@ fn zirAsm( } const constraint = sema.code.nullTerminatedString(output.data.constraint); - needed_capacity += constraint.len / 4 + 1; + const name = sema.code.nullTerminatedString(output.data.name); + needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; break :blk Output{ .constraint = constraint, + .name = name, .ty = try sema.resolveType(block, ret_ty_src, output.data.operand), }; }; @@ -10573,7 +10579,7 @@ fn zirAsm( const constraint = sema.code.nullTerminatedString(input.data.constraint); const name = sema.code.nullTerminatedString(input.data.name); - needed_capacity += (constraint.len + name.len + 1) / 4 + 1; + needed_capacity += (constraint.len + name.len + (2 + 3)) / 4; inputs[arg_i] = .{ .c = constraint, .n = name }; } @@ -10611,7 +10617,9 @@ fn zirAsm( const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); mem.copy(u8, buffer, o.constraint); buffer[o.constraint.len] = 0; - sema.air_extra.items.len += o.constraint.len / 4 + 1; + mem.copy(u8, buffer[o.constraint.len + 1 ..], o.name); + buffer[o.constraint.len + 1 + o.name.len] = 0; + sema.air_extra.items.len += (o.constraint.len + o.name.len + (2 + 3)) / 4; } for (inputs) |input| { const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); @@ -10619,7 +10627,7 @@ fn zirAsm( buffer[input.c.len] = 0; mem.copy(u8, buffer[input.c.len + 1 ..], input.n); buffer[input.c.len + 1 + input.n.len] = 0; - sema.air_extra.items.len += (input.c.len + input.n.len + 1) / 4 + 1; + sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4; } for (clobbers) |clobber| { const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 5ed7b63db3..3b27633f69 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -3272,10 +3272,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output != .none) { return self.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -3283,10 +3285,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { for (inputs) |input| { const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 73f51f6481..87d51b0276 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4078,10 +4078,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output != .none) { return self.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -4089,10 +4091,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { for (inputs) |input| { const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 61fddee207..96d30c31ce 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -2098,10 +2098,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output != .none) { return self.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -2109,10 +2111,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { for (inputs) |input| { const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig index bcd8cf8eeb..7d93916fc1 100644 --- a/src/arch/sparcv9/CodeGen.zig +++ b/src/arch/sparcv9/CodeGen.zig @@ -642,10 +642,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output != .none) { return self.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -653,10 +655,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { for (inputs) |input| { const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index ed85874413..c8dab1c500 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -4738,10 +4738,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output != .none) { return self.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -4749,10 +4751,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { for (inputs) |input| { const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 2cd93d47fc..44b616c493 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3018,10 +3018,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (output != .none) { return f.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const inputs_extra_begin = extra_i; for (inputs) |input, i| { - const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); + const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(input_bytes, 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { const reg = constraint[1 .. constraint.len - 1]; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c9ea5bebac..6c74fc8223 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -340,6 +340,10 @@ pub const Object = struct { llvm_module.setModuleDataLayout(target_data); + if (options.pic) llvm_module.setModulePICLevel(); + if (options.pie) llvm_module.setModulePIELevel(); + if (code_model != .Default) llvm_module.setModuleCodeModel(code_model); + return Object{ .gpa = gpa, .module = options.module.?, @@ -4577,6 +4581,10 @@ pub const FuncGen = struct { const operand_ty = self.air.typeOf(pl_op.operand); const name = self.air.nullTerminatedString(pl_op.payload); + if (needDbgVarWorkaround(self.dg, operand_ty)) { + return null; + } + const di_local_var = dib.createAutoVariable( self.di_scope.?, name.ptr, @@ -4638,14 +4646,19 @@ pub const FuncGen = struct { var llvm_param_i: usize = 0; var total_i: usize = 0; + var name_map: std.StringArrayHashMapUnmanaged(void) = .{}; + try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len); + for (outputs) |output| { if (output != .none) { return self.todo("implement inline asm with non-returned output", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1); if (total_i != 0) { @@ -4654,17 +4667,17 @@ pub const FuncGen = struct { llvm_constraints.appendAssumeCapacity('='); llvm_constraints.appendSliceAssumeCapacity(constraint[1..]); + name_map.putAssumeCapacityNoClobber(name, {}); total_i += 1; } - const input_start_extra_i = extra_i; for (inputs) |input| { - const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; const arg_llvm_value = try self.resolveInst(input); @@ -4677,6 +4690,7 @@ pub const FuncGen = struct { } llvm_constraints.appendSliceAssumeCapacity(constraint); + name_map.putAssumeCapacityNoClobber(name, {}); llvm_param_i += 1; total_i += 1; } @@ -4739,20 +4753,11 @@ pub const FuncGen = struct { const name = asm_source[name_start..i]; state = .start; - extra_i = input_start_extra_i; - for (inputs) |_, input_i| { - const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; - - if (std.mem.eql(u8, name, input_name)) { - try rendered_template.writer().print("{d}", .{input_i}); - break; - } - } else { - return self.todo("TODO validate asm in Sema", .{}); - } + const index = name_map.getIndex(name) orelse { + // we should validate the assembly in Sema; by now it is too late + return self.todo("unknown input or output name: '{s}'", .{name}); + }; + try rendered_template.writer().print("{d}", .{index}); }, else => {}, }, @@ -6150,6 +6155,10 @@ pub const FuncGen = struct { const inst_ty = self.air.typeOfIndex(inst); if (self.dg.object.di_builder) |dib| { + if (needDbgVarWorkaround(self.dg, inst_ty)) { + return arg_val; + } + const src_index = self.getSrcArgIndex(self.arg_index - 1); const func = self.dg.decl.getFunction().?; const lbrace_line = self.dg.module.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; @@ -8251,3 +8260,15 @@ const AnnotatedDITypePtr = enum(usize) { }; const lt_errors_fn_name = "__zig_lt_errors_len"; + +/// Without this workaround, LLVM crashes with "unknown codeview register H1" +/// TODO use llvm-reduce and file upstream LLVM bug for this. +fn needDbgVarWorkaround(dg: *DeclGen, ty: Type) bool { + if (ty.tag() == .f16) { + const target = dg.module.getTarget(); + if (target.os.tag == .windows and target.cpu.arch == .aarch64) { + return true; + } + } + return false; +} diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index b8dc3e1830..560b9544dd 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -310,6 +310,15 @@ pub const Module = opaque { pub const setModuleDataLayout = LLVMSetModuleDataLayout; extern fn LLVMSetModuleDataLayout(*const Module, *const TargetData) void; + pub const setModulePICLevel = ZigLLVMSetModulePICLevel; + extern fn ZigLLVMSetModulePICLevel(module: *const Module) void; + + pub const setModulePIELevel = ZigLLVMSetModulePIELevel; + extern fn ZigLLVMSetModulePIELevel(module: *const Module) void; + + pub const setModuleCodeModel = ZigLLVMSetModuleCodeModel; + extern fn ZigLLVMSetModuleCodeModel(module: *const Module, code_model: CodeModel) void; + pub const addFunction = LLVMAddFunction; extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value; diff --git a/src/print_air.zig b/src/print_air.zig index 6e336e138b..c01d96ed7f 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -542,15 +542,19 @@ const Writer = struct { extra_i += inputs.len; for (outputs) |output| { - const constraint = w.air.nullTerminatedString(extra_i); + const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes - // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + // for the strings and their null terminators, we still use the next u32 + // for the null terminator. + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (output == .none) { - try s.print(", -> {s}", .{constraint}); + try s.print(", [{s}] -> {s}", .{ name, constraint }); } else { - try s.print(", out {s} = (", .{constraint}); + try s.print(", [{s}] out {s} = (", .{ name, constraint }); try w.writeOperand(s, inst, op_index, output); op_index += 1; try s.writeByte(')'); @@ -558,12 +562,15 @@ const Writer = struct { } for (inputs) |input| { - const constraint = w.air.nullTerminatedString(extra_i); + const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes - // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + // for the strings and their null terminators, we still use the next u32 + // for the null terminator. + extra_i += (constraint.len + name.len + 1) / 4 + 1; - try s.print(", in {s} = (", .{constraint}); + try s.print(", [{s}] in {s} = (", .{ name, constraint }); try w.writeOperand(s, inst, op_index, input); op_index += 1; try s.writeByte(')'); @@ -572,7 +579,8 @@ const Writer = struct { { var clobber_i: u32 = 0; while (clobber_i < clobbers_len) : (clobber_i += 1) { - const clobber = w.air.nullTerminatedString(extra_i); + const extra_bytes = std.mem.sliceAsBytes(w.air.extra[extra_i..]); + const clobber = std.mem.sliceTo(extra_bytes, 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. extra_i += clobber.len / 4 + 1; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 89f6e20aa0..b05126db62 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -421,21 +421,10 @@ test "packed struct 24bits" { if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO comptime { - // TODO Remove if and leave only the else branch when it is also fixed in stage2 - if (builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_x86 or - builtin.zig_backend == .stage2_riscv64) - { - // Stage 2 still expects the wrong values - try expect(@sizeOf(Foo24Bits) == 4); - if (@sizeOf(usize) == 4) { - try expect(@sizeOf(Foo96Bits) == 12); - } else { - try expect(@sizeOf(Foo96Bits) == 16); - } - } else { - // Stage1 is now fixed and is expected to return right values - try expectEqual(@sizeOf(Foo24Bits), 3); - try expectEqual(@sizeOf(Foo96Bits), 12); + // stage1 gets the wrong answer for sizeof + if (builtin.zig_backend != .stage1) { + std.debug.assert(@sizeOf(Foo24Bits) == @sizeOf(u24)); + std.debug.assert(@sizeOf(Foo96Bits) == @sizeOf(u96)); } } diff --git a/test/incremental/aarch64-macos/hello_world_with_updates.0.zig b/test/incremental/aarch64-macos/hello_world_with_updates.0.zig index 11a379a9a9..300baac1a4 100644 --- a/test/incremental/aarch64-macos/hello_world_with_updates.0.zig +++ b/test/incremental/aarch64-macos/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=aarch64-macos // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' +// :107:9: error: struct 'tmp.tmp' has no member named 'main' diff --git a/test/incremental/x86_64-linux/hello_world_with_updates.0.zig b/test/incremental/x86_64-linux/hello_world_with_updates.0.zig index 960fae5e64..47b5e9db7a 100644 --- a/test/incremental/x86_64-linux/hello_world_with_updates.0.zig +++ b/test/incremental/x86_64-linux/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=x86_64-linux // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' +// :107:9: error: struct 'tmp.tmp' has no member named 'main' diff --git a/test/incremental/x86_64-macos/hello_world_with_updates.0.zig b/test/incremental/x86_64-macos/hello_world_with_updates.0.zig index 34440c4603..dd43748e6e 100644 --- a/test/incremental/x86_64-macos/hello_world_with_updates.0.zig +++ b/test/incremental/x86_64-macos/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=x86_64-macos // -// :109:9: error: struct 'tmp.tmp' has no member named 'main' +// :107:9: error: struct 'tmp.tmp' has no member named 'main'