Merge pull request #11571 from ziglang/stage2-test-behavior

progress towards stage2 behavior tests for all targets passing with the LLVM backend
This commit is contained in:
Andrew Kelley 2022-05-03 14:58:46 -04:00 committed by GitHub
commit 3cfde183f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 190 additions and 111 deletions

View File

@ -2693,7 +2693,10 @@ pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
pub const MEM_DECOMMIT = 0x4000; pub const MEM_DECOMMIT = 0x4000;
pub const MEM_RELEASE = 0x8000; 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 LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
pub const WIN32_FIND_DATAW = extern struct { 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_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
pub const IMAGE_TLS_DIRECTORY32 = 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; 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_OLD_NAME = 0x00000004;
pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; 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_CREATION = 64;
pub const FILE_NOTIFY_CHANGE_SIZE = 8; 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 CRITICAL_SECTION = RTL_CRITICAL_SECTION;
pub const INIT_ONCE = RTL_RUN_ONCE; pub const INIT_ONCE = RTL_RUN_ONCE;
pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; 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 { pub const RTL_RUN_ONCE = extern struct {
Ptr: ?*anyopaque, Ptr: ?*anyopaque,
@ -3230,7 +3242,10 @@ pub const EXCEPTION_POINTERS = extern struct {
ContextRecord: *std.os.windows.CONTEXT, 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 { pub const OBJECT_ATTRIBUTES = extern struct {
Length: ULONG, Length: ULONG,
@ -3506,7 +3521,10 @@ pub const RTL_DRIVE_LETTER_CURDIR = extern struct {
DosPath: UNICODE_STRING, 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 { pub const FILE_BOTH_DIR_INFORMATION = extern struct {
NextEntryOffset: ULONG, 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 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 { pub const CURDIR = extern struct {
DosPath: UNICODE_STRING, DosPath: UNICODE_STRING,
@ -3598,8 +3619,14 @@ pub const ENUM_PAGE_FILE_INFORMATION = extern struct {
PeakUsage: SIZE_T, PeakUsage: SIZE_T,
}; };
pub const PENUM_PAGE_FILE_CALLBACKW = ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCWSTR) callconv(.C) BOOL; pub const PENUM_PAGE_FILE_CALLBACKW = switch (builtin.zig_backend) {
pub const PENUM_PAGE_FILE_CALLBACKA = ?fn (?LPVOID, *ENUM_PAGE_FILE_INFORMATION, LPCSTR) callconv(.C) BOOL; .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 { pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {
BasicInfo: PSAPI_WS_WATCH_INFORMATION, 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_LOGOFF_EVENT: DWORD = 5;
pub const CTRL_SHUTDOWN_EVENT: DWORD = 6; 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,
};

View File

@ -14,7 +14,7 @@ const ArrayList = std.ArrayList;
// documentation and/or contributors. // documentation and/or contributors.
// https://llvm.org/docs/PDB/DbiStream.html#stream-header // https://llvm.org/docs/PDB/DbiStream.html#stream-header
pub const DbiStreamHeader = packed struct { pub const DbiStreamHeader = extern struct {
VersionSignature: i32, VersionSignature: i32,
VersionHeader: u32, VersionHeader: u32,
Age: u32, Age: u32,
@ -37,7 +37,7 @@ pub const DbiStreamHeader = packed struct {
Padding: u32, Padding: u32,
}; };
pub const SectionContribEntry = packed struct { pub const SectionContribEntry = extern struct {
/// COFF Section index, 1-based /// COFF Section index, 1-based
Section: u16, Section: u16,
Padding1: [2]u8, Padding1: [2]u8,
@ -50,7 +50,7 @@ pub const SectionContribEntry = packed struct {
RelocCrc: u32, RelocCrc: u32,
}; };
pub const ModInfo = packed struct { pub const ModInfo = extern struct {
Unused1: u32, Unused1: u32,
SectionContr: SectionContribEntry, SectionContr: SectionContribEntry,
Flags: u16, Flags: u16,
@ -68,7 +68,7 @@ pub const ModInfo = packed struct {
//ObjFileName: char[], //ObjFileName: char[],
}; };
pub const SectionMapHeader = packed struct { pub const SectionMapHeader = extern struct {
/// Number of segment descriptors /// Number of segment descriptors
Count: u16, Count: u16,
@ -76,7 +76,7 @@ pub const SectionMapHeader = packed struct {
LogCount: u16, LogCount: u16,
}; };
pub const SectionMapEntry = packed struct { pub const SectionMapEntry = extern struct {
/// See the SectionMapEntryFlags enum below. /// See the SectionMapEntryFlags enum below.
Flags: u16, Flags: u16,
@ -310,7 +310,7 @@ pub const SymbolKind = enum(u16) {
pub const TypeIndex = u32; pub const TypeIndex = u32;
pub const ProcSym = packed struct { pub const ProcSym = extern struct {
Parent: u32, Parent: u32,
End: u32, End: u32,
Next: 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. /// Record length, starting from &RecordKind.
RecordLen: u16, RecordLen: u16,
@ -354,7 +354,7 @@ pub const RecordPrefix = packed struct {
/// The structure definition follows. /// The structure definition follows.
/// LineBlockFragmentHeader Blocks[] /// LineBlockFragmentHeader Blocks[]
/// Each `LineBlockFragmentHeader` as specified below. /// Each `LineBlockFragmentHeader` as specified below.
pub const LineFragmentHeader = packed struct { pub const LineFragmentHeader = extern struct {
/// Code offset of line contribution. /// Code offset of line contribution.
RelocOffset: u32, RelocOffset: u32,
@ -376,7 +376,7 @@ pub const LineFlags = packed struct {
/// header. The structure definitions follow. /// header. The structure definitions follow.
/// LineNumberEntry Lines[NumLines]; /// LineNumberEntry Lines[NumLines];
/// ColumnNumberEntry Columns[NumLines]; /// ColumnNumberEntry Columns[NumLines];
pub const LineBlockFragmentHeader = packed struct { pub const LineBlockFragmentHeader = extern struct {
/// Offset of FileChecksum entry in File /// Offset of FileChecksum entry in File
/// checksums buffer. The checksum entry then /// checksums buffer. The checksum entry then
/// contains another offset into the string /// contains another offset into the string
@ -388,7 +388,7 @@ pub const LineBlockFragmentHeader = packed struct {
BlockSize: u32, BlockSize: u32,
}; };
pub const LineNumberEntry = packed struct { pub const LineNumberEntry = extern struct {
/// Offset to start of code bytes for line number /// Offset to start of code bytes for line number
Offset: u32, Offset: u32,
Flags: u32, Flags: u32,
@ -404,13 +404,13 @@ pub const LineNumberEntry = packed struct {
}; };
}; };
pub const ColumnNumberEntry = packed struct { pub const ColumnNumberEntry = extern struct {
StartColumn: u16, StartColumn: u16,
EndColumn: u16, EndColumn: u16,
}; };
/// Checksum bytes follow. /// Checksum bytes follow.
pub const FileChecksumEntryHeader = packed struct { pub const FileChecksumEntryHeader = extern struct {
/// Byte offset of filename in global string table. /// Byte offset of filename in global string table.
FileNameOffset: u32, FileNameOffset: u32,
@ -441,7 +441,7 @@ pub const DebugSubsectionKind = enum(u32) {
CoffSymbolRVA = 0xfd, CoffSymbolRVA = 0xfd,
}; };
pub const DebugSubsectionHeader = packed struct { pub const DebugSubsectionHeader = extern struct {
/// codeview::DebugSubsectionKind enum /// codeview::DebugSubsectionKind enum
Kind: DebugSubsectionKind, Kind: DebugSubsectionKind,
@ -449,7 +449,7 @@ pub const DebugSubsectionHeader = packed struct {
Length: u32, Length: u32,
}; };
pub const PDBStringTableHeader = packed struct { pub const PDBStringTableHeader = extern struct {
/// PDBStringTableSignature /// PDBStringTableSignature
Signature: u32, Signature: u32,
@ -686,12 +686,12 @@ pub const Pdb = struct {
var symbol_i: usize = 0; var symbol_i: usize = 0;
while (symbol_i != module.symbols.len) { 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) if (prefix.RecordLen < 2)
return null; return null;
switch (prefix.RecordKind) { switch (prefix.RecordKind) {
.S_LPROC32, .S_GPROC32 => { .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) { if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) {
return mem.sliceTo(@ptrCast([*:0]u8, proc_sym) + @sizeOf(ProcSym), 0); return mem.sliceTo(@ptrCast([*:0]u8, proc_sym) + @sizeOf(ProcSym), 0);
} }
@ -712,7 +712,7 @@ pub const Pdb = struct {
var skip_len: usize = undefined; var skip_len: usize = undefined;
const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo;
while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { 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; skip_len = subsect_hdr.Length;
sect_offset += @sizeOf(DebugSubsectionHeader); sect_offset += @sizeOf(DebugSubsectionHeader);
@ -720,7 +720,7 @@ pub const Pdb = struct {
.Lines => { .Lines => {
var line_index = sect_offset; 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) if (line_hdr.RelocSegment == 0)
return error.MissingDebugInfo; return error.MissingDebugInfo;
line_index += @sizeOf(LineFragmentHeader); line_index += @sizeOf(LineFragmentHeader);
@ -734,7 +734,7 @@ pub const Pdb = struct {
const subsection_end_index = sect_offset + subsect_hdr.Length; const subsection_end_index = sect_offset + subsect_hdr.Length;
while (line_index < subsection_end_index) { 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); line_index += @sizeOf(LineBlockFragmentHeader);
const start_line_index = line_index; const start_line_index = line_index;
@ -746,7 +746,7 @@ pub const Pdb = struct {
// This is done with a simple linear search. // This is done with a simple linear search.
var line_i: u32 = 0; var line_i: u32 = 0;
while (line_i < block_hdr.NumLines) : (line_i += 1) { 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); line_index += @sizeOf(LineNumberEntry);
const vaddr_start = frag_vaddr_start + line_num_entry.Offset; 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. // line_i == 0 would mean that no matching LineNumberEntry was found.
if (line_i > 0) { if (line_i > 0) {
const subsect_index = checksum_offset + block_hdr.NameIndex; 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; const strtab_offset = @sizeOf(PDBStringTableHeader) + chksum_hdr.FileNameOffset;
try self.string_table.?.seekTo(strtab_offset); try self.string_table.?.seekTo(strtab_offset);
const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024); 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 column = if (has_column) blk: {
const start_col_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines; 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_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; break :blk col_num_entry.StartColumn;
} else 0; } else 0;
const found_line_index = start_line_index + line_entry_idx * @sizeOf(LineNumberEntry); 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); const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
return debug.LineInfo{ return debug.LineInfo{
@ -833,7 +833,7 @@ pub const Pdb = struct {
var sect_offset: usize = 0; var sect_offset: usize = 0;
var skip_len: usize = undefined; var skip_len: usize = undefined;
while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) { 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; skip_len = subsect_hdr.Length;
sect_offset += @sizeOf(DebugSubsectionHeader); 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 // 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. /// 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"; const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";

View File

@ -28,7 +28,7 @@ pub fn main() void {
{ {
return main2() catch @panic("test failure"); return main2() catch @panic("test failure");
} }
if (builtin.zig_backend == .stage1) processArgs(); processArgs();
const test_fn_list = builtin.test_functions; const test_fn_list = builtin.test_functions;
var ok_count: usize = 0; var ok_count: usize = 0;
var skip_count: usize = 0; var skip_count: usize = 0;

View File

@ -29,9 +29,7 @@ comptime {
builtin.zig_backend == .stage2_aarch64 or builtin.zig_backend == .stage2_aarch64 or
builtin.zig_backend == .stage2_arm or builtin.zig_backend == .stage2_arm or
builtin.zig_backend == .stage2_riscv64 or builtin.zig_backend == .stage2_riscv64 or
builtin.zig_backend == .stage2_sparcv9 or builtin.zig_backend == .stage2_sparcv9)
(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))
{ {
if (builtin.output_mode == .Exe) { if (builtin.output_mode == .Exe) {
if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) { if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {

View File

@ -815,6 +815,8 @@ pub const VectorCmp = struct {
/// 1. `Inst.Ref` for every inputs_len /// 1. `Inst.Ref` for every inputs_len
/// 2. for every outputs_len /// 2. for every outputs_len
/// - constraint: memory at this position is reinterpreted as a null /// - 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. /// terminated string. pad to the next u32 after the null byte.
/// 3. for every inputs_len /// 3. for every inputs_len
/// - constraint: memory at this position is reinterpreted as a null /// - constraint: memory at this position is reinterpreted as a null

View File

@ -4323,7 +4323,7 @@ pub fn analyzeExport(
const exported_decl = mod.declPtr(exported_decl_index); const exported_decl = mod.declPtr(exported_decl_index);
// TODO run the same checks as we do for C ABI struct fields // TODO run the same checks as we do for C ABI struct fields
switch (exported_decl.ty.zigTypeTag()) { 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 '{}'", .{ else => return sema.fail(block, src, "unable to export type '{}'", .{
exported_decl.ty.fmt(sema.mod), exported_decl.ty.fmt(sema.mod),
}), }),
@ -10535,7 +10535,11 @@ fn zirAsm(
var output_type_bits = extra.data.output_type_bits; var output_type_bits = extra.data.output_type_bits;
var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len; 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: ?Output = if (outputs_len == 0) null else blk: {
const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i);
extra_i = output.end; extra_i = output.end;
@ -10548,10 +10552,12 @@ fn zirAsm(
} }
const constraint = sema.code.nullTerminatedString(output.data.constraint); 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{ break :blk Output{
.constraint = constraint, .constraint = constraint,
.name = name,
.ty = try sema.resolveType(block, ret_ty_src, output.data.operand), .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 constraint = sema.code.nullTerminatedString(input.data.constraint);
const name = sema.code.nullTerminatedString(input.data.name); 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 }; inputs[arg_i] = .{ .c = constraint, .n = name };
} }
@ -10611,7 +10617,9 @@ fn zirAsm(
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, o.constraint); mem.copy(u8, buffer, o.constraint);
buffer[o.constraint.len] = 0; 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| { for (inputs) |input| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
@ -10619,7 +10627,7 @@ fn zirAsm(
buffer[input.c.len] = 0; buffer[input.c.len] = 0;
mem.copy(u8, buffer[input.c.len + 1 ..], input.n); mem.copy(u8, buffer[input.c.len + 1 ..], input.n);
buffer[input.c.len + 1 + input.n.len] = 0; 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| { for (clobbers) |clobber| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());

View File

@ -3272,10 +3272,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output != .none) { if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -3283,10 +3285,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); 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 // 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. // 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] != '}') { if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -4078,10 +4078,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output != .none) { if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -4089,10 +4091,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); 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 // 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. // 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] != '}') { if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -2098,10 +2098,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output != .none) { if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -2109,10 +2111,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); 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 // 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. // 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] != '}') { if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -642,10 +642,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output != .none) { if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -653,10 +655,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); 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 // 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. // 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] != '}') { if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -4738,10 +4738,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output != .none) { if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -4749,10 +4751,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); 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 // 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. // 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] != '}') { if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});

View File

@ -3018,10 +3018,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
if (output != .none) { if (output != .none) {
return f.fail("TODO implement codegen for non-expr asm", .{}); 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 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 // 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. // 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; break constraint;
} else null; } else null;
@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const inputs_extra_begin = extra_i; const inputs_extra_begin = extra_i;
for (inputs) |input, 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 // 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. // 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] == '}') { if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {
const reg = constraint[1 .. constraint.len - 1]; const reg = constraint[1 .. constraint.len - 1];

View File

@ -340,6 +340,10 @@ pub const Object = struct {
llvm_module.setModuleDataLayout(target_data); 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{ return Object{
.gpa = gpa, .gpa = gpa,
.module = options.module.?, .module = options.module.?,
@ -4577,6 +4581,10 @@ pub const FuncGen = struct {
const operand_ty = self.air.typeOf(pl_op.operand); const operand_ty = self.air.typeOf(pl_op.operand);
const name = self.air.nullTerminatedString(pl_op.payload); const name = self.air.nullTerminatedString(pl_op.payload);
if (needDbgVarWorkaround(self.dg, operand_ty)) {
return null;
}
const di_local_var = dib.createAutoVariable( const di_local_var = dib.createAutoVariable(
self.di_scope.?, self.di_scope.?,
name.ptr, name.ptr,
@ -4638,14 +4646,19 @@ pub const FuncGen = struct {
var llvm_param_i: usize = 0; var llvm_param_i: usize = 0;
var total_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| { for (outputs) |output| {
if (output != .none) { if (output != .none) {
return self.todo("implement inline asm with non-returned output", .{}); 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 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 // 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. // 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); try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1);
if (total_i != 0) { if (total_i != 0) {
@ -4654,17 +4667,17 @@ pub const FuncGen = struct {
llvm_constraints.appendAssumeCapacity('='); llvm_constraints.appendAssumeCapacity('=');
llvm_constraints.appendSliceAssumeCapacity(constraint[1..]); llvm_constraints.appendSliceAssumeCapacity(constraint[1..]);
name_map.putAssumeCapacityNoClobber(name, {});
total_i += 1; total_i += 1;
} }
const input_start_extra_i = extra_i;
for (inputs) |input| { for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
const constraint = std.mem.sliceTo(input_bytes, 0); const constraint = std.mem.sliceTo(extra_bytes, 0);
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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 // 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. // 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); const arg_llvm_value = try self.resolveInst(input);
@ -4677,6 +4690,7 @@ pub const FuncGen = struct {
} }
llvm_constraints.appendSliceAssumeCapacity(constraint); llvm_constraints.appendSliceAssumeCapacity(constraint);
name_map.putAssumeCapacityNoClobber(name, {});
llvm_param_i += 1; llvm_param_i += 1;
total_i += 1; total_i += 1;
} }
@ -4739,20 +4753,11 @@ pub const FuncGen = struct {
const name = asm_source[name_start..i]; const name = asm_source[name_start..i];
state = .start; state = .start;
extra_i = input_start_extra_i; const index = name_map.getIndex(name) orelse {
for (inputs) |_, input_i| { // we should validate the assembly in Sema; by now it is too late
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); return self.todo("unknown input or output name: '{s}'", .{name});
const constraint = std.mem.sliceTo(input_bytes, 0); };
const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); try rendered_template.writer().print("{d}", .{index});
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", .{});
}
}, },
else => {}, else => {},
}, },
@ -6150,6 +6155,10 @@ pub const FuncGen = struct {
const inst_ty = self.air.typeOfIndex(inst); const inst_ty = self.air.typeOfIndex(inst);
if (self.dg.object.di_builder) |dib| { 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 src_index = self.getSrcArgIndex(self.arg_index - 1);
const func = self.dg.decl.getFunction().?; const func = self.dg.decl.getFunction().?;
const lbrace_line = self.dg.module.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; 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"; 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;
}

View File

@ -310,6 +310,15 @@ pub const Module = opaque {
pub const setModuleDataLayout = LLVMSetModuleDataLayout; pub const setModuleDataLayout = LLVMSetModuleDataLayout;
extern fn LLVMSetModuleDataLayout(*const Module, *const TargetData) void; 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; pub const addFunction = LLVMAddFunction;
extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value; extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value;

View File

@ -542,15 +542,19 @@ const Writer = struct {
extra_i += inputs.len; extra_i += inputs.len;
for (outputs) |output| { 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 // 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. // for the strings and their null terminators, we still use the next u32
extra_i += constraint.len / 4 + 1; // for the null terminator.
extra_i += (constraint.len + name.len + (2 + 3)) / 4;
if (output == .none) { if (output == .none) {
try s.print(", -> {s}", .{constraint}); try s.print(", [{s}] -> {s}", .{ name, constraint });
} else { } else {
try s.print(", out {s} = (", .{constraint}); try s.print(", [{s}] out {s} = (", .{ name, constraint });
try w.writeOperand(s, inst, op_index, output); try w.writeOperand(s, inst, op_index, output);
op_index += 1; op_index += 1;
try s.writeByte(')'); try s.writeByte(')');
@ -558,12 +562,15 @@ const Writer = struct {
} }
for (inputs) |input| { 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 // 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. // for the strings and their null terminators, we still use the next u32
extra_i += constraint.len / 4 + 1; // 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); try w.writeOperand(s, inst, op_index, input);
op_index += 1; op_index += 1;
try s.writeByte(')'); try s.writeByte(')');
@ -572,7 +579,8 @@ const Writer = struct {
{ {
var clobber_i: u32 = 0; var clobber_i: u32 = 0;
while (clobber_i < clobbers_len) : (clobber_i += 1) { 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 // 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. // for the string, we still use the next u32 for the null terminator.
extra_i += clobber.len / 4 + 1; extra_i += clobber.len / 4 + 1;

View File

@ -421,21 +421,10 @@ test "packed struct 24bits" {
if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
comptime { comptime {
// TODO Remove if and leave only the else branch when it is also fixed in stage2 // stage1 gets the wrong answer for sizeof
if (builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_x86 or if (builtin.zig_backend != .stage1) {
builtin.zig_backend == .stage2_riscv64) std.debug.assert(@sizeOf(Foo24Bits) == @sizeOf(u24));
{ std.debug.assert(@sizeOf(Foo96Bits) == @sizeOf(u96));
// 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);
} }
} }

View File

@ -2,4 +2,4 @@
// output_mode=Exe // output_mode=Exe
// target=aarch64-macos // 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'

View File

@ -2,4 +2,4 @@
// output_mode=Exe // output_mode=Exe
// target=x86_64-linux // 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'

View File

@ -2,4 +2,4 @@
// output_mode=Exe // output_mode=Exe
// target=x86_64-macos // 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'