From c5ba941b77fbdb06841f28142420c6786f2a4d0c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Jul 2022 15:18:36 -0700 Subject: [PATCH 1/8] stage2: all pointers have runtime bits --- src/type.zig | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/type.zig b/src/type.zig index 55847b8adda6..700f5245562b 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2374,6 +2374,18 @@ pub const Type = extern union { .error_union, .error_set, .error_set_merged, + .anyframe_T, + .optional_single_mut_pointer, + .optional_single_const_pointer, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .pointer, => return true, // These are false because they are comptime-only types. @@ -2399,30 +2411,6 @@ pub const Type = extern union { .fn_ccc_void_no_args, => return false, - // These types have more than one possible value, so the result is the same as - // asking whether they are comptime-only types. - .anyframe_T, - .optional_single_mut_pointer, - .optional_single_const_pointer, - .single_const_pointer, - .single_mut_pointer, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .const_slice, - .mut_slice, - .pointer, - => { - if (ignore_comptime_only) { - return true; - } else if (sema_kit) |sk| { - return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); - } else { - return !comptimeOnly(ty); - } - }, - .optional => { var buf: Payload.ElemType = undefined; const child_ty = ty.optionalChild(&buf); From 6e313eb1107d4f5d7b0ada0a67c810ce90e79bf5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Jul 2022 16:27:37 -0700 Subject: [PATCH 2/8] stage2: agree with LLVM that `@alignOf(u128)` is 8 on x86_64 and similar targets. --- lib/std/target.zig | 7 ++++--- src/Module.zig | 30 +++++++++++++++++++++++++----- src/Sema.zig | 5 +---- src/codegen/llvm.zig | 14 ++++++++------ src/type.zig | 13 +++++++++++-- test/behavior/align.zig | 29 +++++++++++++++++++++-------- 6 files changed, 70 insertions(+), 28 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index f77f73bce0ba..155c59bdfcfd 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1806,9 +1806,9 @@ pub const Target = struct { else => 4, }, - // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 16 - // is a better number for two reasons: - // 1. Better machine code when loading into SIMD register. + // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16 + // is a relevant number in three cases: + // 1. Different machine code instruction when loading into SIMD register. // 2. The C ABI wants 16 for extern structs. // 3. 16-byte cmpxchg needs 16-byte alignment. // Same logic for riscv64, powerpc64, mips64, sparc64. @@ -1819,6 +1819,7 @@ pub const Target = struct { .mips64, .mips64el, .sparc64, + => 8, // Even LLVMABIAlignmentOfType(i128) agrees on these targets. .aarch64, diff --git a/src/Module.zig b/src/Module.zig index 995fdda7ea24..6d2180e8e747 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -935,13 +935,33 @@ pub const Struct = struct { /// If true then `default_val` is the comptime field value. is_comptime: bool, - /// Returns the field alignment, assuming the struct is not packed. - pub fn normalAlignment(field: Field, target: Target) u32 { - if (field.abi_align == 0) { - return field.ty.abiAlignment(target); - } else { + /// Returns the field alignment. If the struct is packed, returns 0. + pub fn alignment( + field: Field, + target: Target, + layout: std.builtin.Type.ContainerLayout, + ) u32 { + if (field.abi_align != 0) { + assert(layout != .Packed); return field.abi_align; } + + switch (layout) { + .Packed => return 0, + .Auto => return field.ty.abiAlignment(target), + .Extern => { + // This logic is duplicated in Type.abiAlignmentAdvanced. + const ty_abi_align = field.ty.abiAlignment(target); + + if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { + // The C ABI requires 128 bit integer fields of structs + // to be 16-bytes aligned. + return @maximum(ty_abi_align, 16); + } + + return ty_abi_align; + }, + } } }; diff --git a/src/Sema.zig b/src/Sema.zig index d6ac3d02766a..32b95a4c21be 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14380,10 +14380,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai else field.default_val; const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val); - const alignment = switch (layout) { - .Auto, .Extern => field.normalAlignment(target), - .Packed => 0, - }; + const alignment = field.alignment(target, layout); struct_field_fields.* = .{ // name: []const u8, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 0586c994320b..a9a343439df3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1841,6 +1841,7 @@ pub const Object = struct { } const fields = ty.structFields(); + const layout = ty.containerLayout(); var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; defer di_fields.deinit(gpa); @@ -1854,7 +1855,7 @@ pub const Object = struct { if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; const field_size = field.ty.abiSize(target); - const field_align = field.normalAlignment(target); + const field_align = field.alignment(target, layout); const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); offset = field_offset + field_size; @@ -2499,7 +2500,7 @@ pub const DeclGen = struct { fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { const llvm_ty = try lowerTypeInner(dg, t); - if (std.debug.runtime_safety and false) check: { + if (std.debug.runtime_safety) check: { if (t.zigTypeTag() == .Opaque) break :check; if (!t.hasRuntimeBits()) break :check; if (!llvm_ty.isSized().toBool()) break :check; @@ -2757,7 +2758,7 @@ pub const DeclGen = struct { for (struct_obj.fields.values()) |field| { if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; - const field_align = field.normalAlignment(target); + const field_align = field.alignment(target, struct_obj.layout); const field_ty_align = field.ty.abiAlignment(target); any_underaligned_fields = any_underaligned_fields or field_align < field_ty_align; @@ -3433,7 +3434,7 @@ pub const DeclGen = struct { for (struct_obj.fields.values()) |field, i| { if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; - const field_align = field.normalAlignment(target); + const field_align = field.alignment(target, struct_obj.layout); big_align = @maximum(big_align, field_align); const prev_offset = offset; offset = std.mem.alignForwardGeneric(u64, offset, field_align); @@ -9376,13 +9377,14 @@ fn llvmFieldIndex( } return null; } - assert(ty.containerLayout() != .Packed); + const layout = ty.containerLayout(); + assert(layout != .Packed); var llvm_field_index: c_uint = 0; for (ty.structFields().values()) |field, i| { if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; - const field_align = field.normalAlignment(target); + const field_align = field.alignment(target, layout); big_align = @maximum(big_align, field_align); const prev_offset = offset; offset = std.mem.alignForwardGeneric(u64, offset, field_align); diff --git a/src/type.zig b/src/type.zig index 700f5245562b..4432ae9cf3d2 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3017,6 +3017,15 @@ pub const Type = extern union { }, }; big_align = @maximum(big_align, field_align); + + // This logic is duplicated in Module.Struct.Field.alignment. + if (struct_obj.layout == .Extern) { + if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { + // The C ABI requires 128 bit integer fields of structs + // to be 16-bytes aligned. + big_align = @maximum(big_align, 16); + } + } } return AbiAlignmentAdvanced{ .scalar = big_align }; }, @@ -5490,7 +5499,7 @@ pub const Type = extern union { .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; assert(struct_obj.layout != .Packed); - return struct_obj.fields.values()[index].normalAlignment(target); + return struct_obj.fields.values()[index].alignment(target, struct_obj.layout); }, .@"union", .union_safety_tagged, .union_tagged => { const union_obj = ty.cast(Payload.Union).?.data; @@ -5597,7 +5606,7 @@ pub const Type = extern union { if (!field.ty.hasRuntimeBits() or field.is_comptime) return FieldOffset{ .field = it.field, .offset = it.offset }; - const field_align = field.normalAlignment(it.target); + const field_align = field.alignment(it.target, it.struct_obj.layout); it.big_align = @maximum(it.big_align, field_align); it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); defer it.offset += field.ty.abiSize(it.target); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 26e3d9137335..4a824bc9cf48 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -143,6 +143,19 @@ test "alignment and size of structs with 128-bit fields" { .riscv64, .sparc64, .x86_64, + => .{ + .a_align = 8, + .a_size = 16, + + .b_align = 16, + .b_size = 32, + + .u128_align = 8, + .u128_size = 16, + .u129_align = 8, + .u129_size = 24, + }, + .aarch64, .aarch64_be, .aarch64_32, @@ -166,17 +179,17 @@ test "alignment and size of structs with 128-bit fields" { else => return error.SkipZigTest, }; comptime { - std.debug.assert(@alignOf(A) == expected.a_align); - std.debug.assert(@sizeOf(A) == expected.a_size); + assert(@alignOf(A) == expected.a_align); + assert(@sizeOf(A) == expected.a_size); - std.debug.assert(@alignOf(B) == expected.b_align); - std.debug.assert(@sizeOf(B) == expected.b_size); + assert(@alignOf(B) == expected.b_align); + assert(@sizeOf(B) == expected.b_size); - std.debug.assert(@alignOf(u128) == expected.u128_align); - std.debug.assert(@sizeOf(u128) == expected.u128_size); + assert(@alignOf(u128) == expected.u128_align); + assert(@sizeOf(u128) == expected.u128_size); - std.debug.assert(@alignOf(u129) == expected.u129_align); - std.debug.assert(@sizeOf(u129) == expected.u129_size); + assert(@alignOf(u129) == expected.u129_align); + assert(@sizeOf(u129) == expected.u129_size); } } From 4552ccb6856a84bb88badb265c43114ff57bd90c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Jul 2022 16:48:47 -0700 Subject: [PATCH 3/8] stage2: make `@Vector` ABI size agree with LLVM --- src/type.zig | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/type.zig b/src/type.zig index 4432ae9cf3d2..fb2ca1e3fcb8 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3260,8 +3260,8 @@ pub const Type = extern union { .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data }, .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 }, - .array, .vector => { - const payload = ty.cast(Payload.Array).?.data; + .array => { + const payload = ty.castTag(.array).?.data; switch (try payload.elem_type.abiSizeAdvanced(target, strat)) { .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, .val => switch (strat) { @@ -3283,6 +3283,28 @@ pub const Type = extern union { } }, + .vector => { + const payload = ty.castTag(.vector).?.data; + const sema_kit = switch (strat) { + .sema_kit => |sk| sk, + .eager => null, + .lazy => |arena| return AbiSizeAdvanced{ + .val = try Value.Tag.lazy_size.create(arena, ty), + }, + }; + const elem_bits = try payload.elem_type.bitSizeAdvanced(target, sema_kit); + const total_bits = elem_bits * payload.len; + const total_bytes = (total_bits + 7) / 8; + const alignment = switch (try ty.abiAlignmentAdvanced(target, strat)) { + .scalar => |x| x, + .val => return AbiSizeAdvanced{ + .val = try Value.Tag.lazy_size.create(strat.lazy, ty), + }, + }; + const result = std.mem.alignForwardGeneric(u64, total_bytes, alignment); + return AbiSizeAdvanced{ .scalar = result }; + }, + .isize, .usize, .@"anyframe", From 517eb73b23ee77672abe6b20b79b6648cd3ff879 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Jul 2022 17:03:05 -0700 Subject: [PATCH 4/8] LLVM: disable the ABI size safety check There still more instances of this check being tripped during behavior tests that we need to fix before we can enable this. --- src/codegen/llvm.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a9a343439df3..983813d780c1 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2500,7 +2500,7 @@ pub const DeclGen = struct { fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { const llvm_ty = try lowerTypeInner(dg, t); - if (std.debug.runtime_safety) check: { + if (std.debug.runtime_safety and false) check: { if (t.zigTypeTag() == .Opaque) break :check; if (!t.hasRuntimeBits()) break :check; if (!llvm_ty.isSized().toBool()) break :check; From b975f7a56fec9e0e7aca9832282bc772c743d731 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Aug 2022 18:58:28 -0700 Subject: [PATCH 5/8] std.Target gains ObjectFormat field --- lib/std/target.zig | 33 ++++++++-------- lib/std/zig.zig | 12 +++--- lib/std/zig/CrossTarget.zig | 13 ++++++- lib/std/zig/system/NativeTargetInfo.zig | 5 +++ src/Compilation.zig | 30 +++++++-------- src/Sema.zig | 2 +- src/codegen/llvm.zig | 2 +- src/link.zig | 11 +++--- src/link/C.zig | 2 +- src/link/Coff.zig | 2 +- src/link/Elf.zig | 2 +- src/link/MachO.zig | 4 +- src/link/NvPtx.zig | 2 +- src/link/Plan9.zig | 2 +- src/link/SpirV.zig | 2 +- src/link/Wasm.zig | 2 +- src/main.zig | 51 +++++++++++-------------- src/stage1/codegen.cpp | 1 + 18 files changed, 93 insertions(+), 85 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index 155c59bdfcfd..00553bb52079 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -9,6 +9,7 @@ pub const Target = struct { cpu: Cpu, os: Os, abi: Abi, + ofmt: ObjectFormat, pub const Os = struct { tag: Tag, @@ -594,6 +595,20 @@ pub const Target = struct { .nvptx => ".ptx", }; } + + pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { + return switch (os_tag) { + .windows, .uefi => .coff, + .ios, .macos, .watchos, .tvos => .macho, + .plan9 => .plan9, + else => return switch (cpu_arch) { + .wasm32, .wasm64 => .wasm, + .spirv32, .spirv64 => .spirv, + .nvptx, .nvptx64 => .nvptx, + else => .elf, + }, + }; + } }; pub const SubSystem = enum { @@ -1381,24 +1396,6 @@ pub const Target = struct { return libPrefix_os_abi(self.os.tag, self.abi); } - pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat { - return switch (os_tag) { - .windows, .uefi => .coff, - .ios, .macos, .watchos, .tvos => .macho, - .plan9 => .plan9, - else => return switch (cpu_arch) { - .wasm32, .wasm64 => .wasm, - .spirv32, .spirv64 => .spirv, - .nvptx, .nvptx64 => .nvptx, - else => .elf, - }, - }; - } - - pub fn getObjectFormat(self: Target) ObjectFormat { - return getObjectFormatSimple(self.os.tag, self.cpu.arch); - } - pub fn isMinGW(self: Target) bool { return self.os.tag == .windows and self.isGnu(); } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index b8f75f649eef..85835ebf1880 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -103,7 +103,6 @@ pub const BinNameOptions = struct { target: std.Target, output_mode: std.builtin.OutputMode, link_mode: ?std.builtin.LinkMode = null, - object_format: ?std.Target.ObjectFormat = null, version: ?std.builtin.Version = null, }; @@ -111,8 +110,7 @@ pub const BinNameOptions = struct { pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 { const root_name = options.root_name; const target = options.target; - const ofmt = options.object_format orelse target.getObjectFormat(); - switch (ofmt) { + switch (target.ofmt) { .coff => switch (options.output_mode) { .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }), .Lib => { @@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}), .plan9 => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), - .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }), - .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }), + .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ + root_name, target.ofmt.fileExt(target.cpu.arch), + }), + .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ + target.libPrefix(), root_name, + }), }, .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}), } diff --git a/lib/std/zig/CrossTarget.zig b/lib/std/zig/CrossTarget.zig index 196afbc83560..a4e9b2576d41 100644 --- a/lib/std/zig/CrossTarget.zig +++ b/lib/std/zig/CrossTarget.zig @@ -42,6 +42,9 @@ abi: ?Target.Abi = null, /// based on the `os_tag`. dynamic_linker: DynamicLinker = DynamicLinker{}, +/// `null` means default for the cpu/arch/os combo. +ofmt: ?Target.ObjectFormat = null, + pub const CpuModel = union(enum) { /// Always native native, @@ -168,6 +171,7 @@ pub fn toTarget(self: CrossTarget) Target { .cpu = self.getCpu(), .os = self.getOs(), .abi = self.getAbi(), + .ofmt = self.getObjectFormat(), }; } @@ -197,6 +201,8 @@ pub const ParseOptions = struct { /// detected path, or a standard path. dynamic_linker: ?[]const u8 = null, + object_format: ?[]const u8 = null, + /// If this is provided, the function will populate some information about parsing failures, /// so that user-friendly error messages can be delivered. diagnostics: ?*Diagnostics = null, @@ -321,6 +327,11 @@ pub fn parse(args: ParseOptions) !CrossTarget { } } + if (args.object_format) |ofmt_name| { + result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse + return error.UnknownObjectFormat; + } + return result; } @@ -620,7 +631,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) } pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat { - return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch()); + return self.ofmt orelse Target.ObjectFormat.default(self.getOsTag(), self.getCpuArch()); } pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void { diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig index 6dcedd93b8c8..4f8c0025c5dd 100644 --- a/lib/std/zig/system/NativeTargetInfo.zig +++ b/lib/std/zig/system/NativeTargetInfo.zig @@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker( }; var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; var ld_info_list_len: usize = 0; + const ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch); for (all_abis) |abi| { // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and @@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker( .cpu = cpu, .os = os, .abi = abi, + .ofmt = ofmt, }; const ld = target.standardDynamicLinkerPath(); if (ld.get() == null) continue; @@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker( .cpu = cpu, .os = os_adjusted, .abi = cross_target.abi orelse found_ld_info.abi, + .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os_adjusted.tag, cpu.arch), }, .dynamic_linker = if (cross_target.dynamic_linker.get() == null) DynamicLinker.init(found_ld_path) @@ -539,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile( .cpu = cpu, .os = os, .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), + .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), }, .dynamic_linker = cross_target.dynamic_linker, }; @@ -829,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros .cpu = cpu, .os = os, .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os), + .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), }; return NativeTargetInfo{ .target = target, diff --git a/src/Compilation.zig b/src/Compilation.zig index af39154a3f23..5e0d815c9620 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -810,7 +810,6 @@ pub const InitOptions = struct { /// this flag would be set to disable this machinery to avoid false positives. disable_lld_caching: bool = false, cache_mode: CacheMode = .incremental, - object_format: ?std.Target.ObjectFormat = null, optimize_mode: std.builtin.Mode = .Debug, keep_source_files_loaded: bool = false, clang_argv: []const []const u8 = &[0][]const u8{}, @@ -1027,8 +1026,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const comp = try arena.create(Compilation); const root_name = try arena.dupeZ(u8, options.root_name); - const ofmt = options.object_format orelse options.target.getObjectFormat(); - const use_stage1 = options.use_stage1 orelse blk: { // Even though we may have no Zig code to compile (depending on `options.main_pkg`), // we may need to use stage1 for building compiler-rt and other dependencies. @@ -1042,7 +1039,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } // If LLVM does not support the target, then we can't use it. - if (!target_util.hasLlvmSupport(options.target, ofmt)) + if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) break :blk false; break :blk build_options.is_stage1; @@ -1072,7 +1069,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { break :blk true; // If LLVM does not support the target, then we can't use it. - if (!target_util.hasLlvmSupport(options.target, ofmt)) + if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) break :blk false; // Prefer LLVM for release builds. @@ -1115,7 +1112,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (!build_options.have_llvm) break :blk false; - if (ofmt == .c) + if (options.target.ofmt == .c) break :blk false; if (options.want_lto) |lto| { @@ -1374,7 +1371,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { cache.hash.add(options.target.os.getVersionRange()); cache.hash.add(options.is_native_os); cache.hash.add(options.target.abi); - cache.hash.add(ofmt); + cache.hash.add(options.target.ofmt); cache.hash.add(pic); cache.hash.add(pie); cache.hash.add(lto); @@ -1682,7 +1679,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .sysroot = sysroot, .output_mode = options.output_mode, .link_mode = link_mode, - .object_format = ofmt, .optimize_mode = options.optimize_mode, .use_lld = use_lld, .use_llvm = use_llvm, @@ -1841,7 +1837,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; - if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies) { + if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and + options.target.ofmt != .c) + { if (comp.getTarget().isDarwin()) { switch (comp.getTarget().abi) { .none, @@ -3739,7 +3737,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P else c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; - const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch); + const target = comp.getTarget(); + const o_ext = target.ofmt.fileExt(target.cpu.arch); const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { var argv = std.ArrayList([]const u8).init(comp.gpa); defer argv.deinit(); @@ -4092,7 +4091,7 @@ pub fn addCCArgs( if (!comp.bin_file.options.strip) { try argv.append("-g"); - switch (comp.bin_file.options.object_format) { + switch (target.ofmt) { .coff => try argv.append("-gcodeview"), else => {}, } @@ -4660,7 +4659,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { }; return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and comp.bin_file.options.libc_installation == null and - comp.bin_file.options.object_format != .c; + comp.bin_file.options.target.ofmt != .c; } fn wantBuildGLibCFromSource(comp: Compilation) bool { @@ -4688,7 +4687,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { .Exe => true, }; return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and - comp.bin_file.options.object_format != .c; + comp.bin_file.options.target.ofmt != .c; } fn setAllocFailure(comp: *Compilation) void { @@ -4747,7 +4746,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca const zig_backend: std.builtin.CompilerBackend = blk: { if (use_stage1) break :blk .stage1; if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm; - if (comp.bin_file.options.object_format == .c) break :blk .stage2_c; + if (target.ofmt == .c) break :blk .stage2_c; break :blk switch (target.cpu.arch) { .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, .arm, .armeb, .thumb, .thumbeb => .stage2_arm, @@ -4895,6 +4894,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca \\ .cpu = cpu, \\ .os = os, \\ .abi = abi, + \\ .ofmt = object_format, \\}}; \\pub const object_format = std.Target.ObjectFormat.{}; \\pub const mode = std.builtin.Mode.{}; @@ -4909,7 +4909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca \\pub const code_model = std.builtin.CodeModel.{}; \\ , .{ - std.zig.fmtId(@tagName(comp.bin_file.options.object_format)), + std.zig.fmtId(@tagName(target.ofmt)), std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)), link_libc, comp.bin_file.options.link_libcpp, diff --git a/src/Sema.zig b/src/Sema.zig index 32b95a4c21be..d059ee09a39d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20654,7 +20654,7 @@ fn panicWithMsg( const arena = sema.arena; const this_feature_is_implemented_in_the_backend = - mod.comp.bin_file.options.object_format == .c or + mod.comp.bin_file.options.target.ofmt == .c or mod.comp.bin_file.options.use_llvm; if (!this_feature_is_implemented_in_the_backend) { // TODO implement this feature in all the backends and then delete this branch diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 983813d780c1..8c84f61a81e7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -273,7 +273,7 @@ pub const Object = struct { var di_compile_unit: ?*llvm.DICompileUnit = null; if (!options.strip) { - switch (options.object_format) { + switch (options.target.ofmt) { .coff => llvm_module.addModuleCodeViewFlag(), else => llvm_module.addModuleDebugInfoFlag(), } diff --git a/src/link.zig b/src/link.zig index a6dafce20e5b..31b54f705a1c 100644 --- a/src/link.zig +++ b/src/link.zig @@ -72,7 +72,6 @@ pub const Options = struct { target: std.Target, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, - object_format: std.Target.ObjectFormat, optimize_mode: std.builtin.Mode, machine_code_model: std.builtin.CodeModel, root_name: [:0]const u8, @@ -273,13 +272,13 @@ pub const File = struct { /// rewriting it. A malicious file is detected as incremental link failure /// and does not cause Illegal Behavior. This operation is not atomic. pub fn openPath(allocator: Allocator, options: Options) !*File { - if (options.object_format == .macho) { + if (options.target.ofmt == .macho) { return &(try MachO.openPath(allocator, options)).base; } const use_stage1 = build_options.is_stage1 and options.use_stage1; if (use_stage1 or options.emit == null) { - return switch (options.object_format) { + return switch (options.target.ofmt) { .coff => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, .macho => unreachable, @@ -298,7 +297,7 @@ pub const File = struct { if (options.module == null) { // No point in opening a file, we would not write anything to it. // Initialize with empty. - return switch (options.object_format) { + return switch (options.target.ofmt) { .coff => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, .macho => unreachable, @@ -314,12 +313,12 @@ pub const File = struct { // Open a temporary object file, not the final output file because we // want to link with LLD. break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ - emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), + emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), }); } else emit.sub_path; errdefer if (use_lld) allocator.free(sub_path); - const file: *File = switch (options.object_format) { + const file: *File = switch (options.target.ofmt) { .coff => &(try Coff.openPath(allocator, sub_path, options)).base, .elf => &(try Elf.openPath(allocator, sub_path, options)).base, .macho => unreachable, diff --git a/src/link/C.zig b/src/link/C.zig index 6449be9c56fb..955044f90d46 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -48,7 +48,7 @@ const DeclBlock = struct { }; pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C { - assert(options.object_format == .c); + assert(options.target.ofmt == .c); if (options.use_llvm) return error.LLVMHasNoCBackend; if (options.use_lld) return error.LLDHasNoCBackend; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 1b5ddbbf8b52..92e9dce3ad28 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -128,7 +128,7 @@ pub const TextBlock = struct { pub const SrcFn = void; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { - assert(options.object_format == .coff); + assert(options.target.ofmt == .coff); if (build_options.have_llvm and options.use_llvm) { return createEmpty(allocator, options); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 917e4c18d117..2f67c352054f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -249,7 +249,7 @@ pub const Export = struct { }; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf { - assert(options.object_format == .elf); + assert(options.target.ofmt == .elf); if (build_options.have_llvm and options.use_llvm) { return createEmpty(allocator, options); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index e4370c703e39..7a5084302363 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -270,7 +270,7 @@ pub const Export = struct { }; pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { - assert(options.object_format == .macho); + assert(options.target.ofmt == .macho); const use_stage1 = build_options.is_stage1 and options.use_stage1; if (use_stage1 or options.emit == null) { @@ -289,7 +289,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { // we also want to put the intermediary object file in the cache while the // main emit directory is the cwd. self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{ - emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), + emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), }); } diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index bd86d8720105..7bf51c7ad3fc 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx { if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled."); if (!options.use_llvm) return error.PtxArchNotSupported; - assert(options.object_format == .nvptx); + assert(options.target.ofmt == .nvptx); const nvptx = try createEmpty(allocator, options); log.info("Opening .ptx target file {s}", .{sub_path}); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 16f7841c2d7d..9a8927dcb4dd 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -657,7 +657,7 @@ pub const base_tag = .plan9; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { if (options.use_llvm) return error.LLVMBackendDoesNotSupportPlan9; - assert(options.object_format == .plan9); + assert(options.target.ofmt == .plan9); const self = try createEmpty(allocator, options); errdefer self.base.destroy(); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index e295dceb559e..b2f6edddfb4e 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV { } pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV { - assert(options.object_format == .spirv); + assert(options.target.ofmt == .spirv); if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all. if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 1bdd9426a58b..626786588873 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -282,7 +282,7 @@ pub const StringTable = struct { }; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm { - assert(options.object_format == .wasm); + assert(options.target.ofmt == .wasm); if (build_options.have_llvm and options.use_llvm) { return createEmpty(allocator, options); diff --git a/src/main.zig b/src/main.zig index 971fe19e36c6..dfce4d83b88e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2192,6 +2192,7 @@ fn buildOutputType( .arch_os_abi = target_arch_os_abi, .cpu_features = target_mcpu, .dynamic_linker = target_dynamic_linker, + .object_format = target_ofmt, }; // Before passing the mcpu string in for parsing, we convert any -m flags that were @@ -2494,28 +2495,7 @@ fn buildOutputType( } } - const object_format: std.Target.ObjectFormat = blk: { - const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat(); - if (mem.eql(u8, ofmt, "elf")) { - break :blk .elf; - } else if (mem.eql(u8, ofmt, "c")) { - break :blk .c; - } else if (mem.eql(u8, ofmt, "coff")) { - break :blk .coff; - } else if (mem.eql(u8, ofmt, "macho")) { - break :blk .macho; - } else if (mem.eql(u8, ofmt, "wasm")) { - break :blk .wasm; - } else if (mem.eql(u8, ofmt, "hex")) { - break :blk .hex; - } else if (mem.eql(u8, ofmt, "raw")) { - break :blk .raw; - } else if (mem.eql(u8, ofmt, "spirv")) { - break :blk .spirv; - } else { - fatal("unsupported object format: {s}", .{ofmt}); - } - }; + const object_format = target_info.target.ofmt; if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) { const total_obj_count = c_source_files.items.len + @@ -2569,7 +2549,6 @@ fn buildOutputType( .target = target_info.target, .output_mode = output_mode, .link_mode = link_mode, - .object_format = object_format, .version = optional_version, }), }, @@ -2859,7 +2838,6 @@ fn buildOutputType( .emit_implib = emit_implib_resolved.data, .link_mode = link_mode, .dll_export_fns = dll_export_fns, - .object_format = object_format, .optimize_mode = optimize_mode, .keep_source_files_loaded = false, .clang_argv = clang_argv.items, @@ -3173,11 +3151,11 @@ fn parseCrossTargetOrReportFatalError( for (diags.arch.?.allCpuModels()) |cpu| { help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help; } - std.log.info("Available CPUs for architecture '{s}':\n{s}", .{ + std.log.info("available CPUs for architecture '{s}':\n{s}", .{ @tagName(diags.arch.?), help_text.items, }); } - fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?}); + fatal("unknown CPU: '{s}'", .{diags.cpu_name.?}); }, error.UnknownCpuFeature => { help: { @@ -3186,11 +3164,26 @@ fn parseCrossTargetOrReportFatalError( for (diags.arch.?.allFeaturesList()) |feature| { help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help; } - std.log.info("Available CPU features for architecture '{s}':\n{s}", .{ + std.log.info("available CPU features for architecture '{s}':\n{s}", .{ @tagName(diags.arch.?), help_text.items, }); } - fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?}); + fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?}); + }, + error.UnknownObjectFormat => { + { + var help_text = std.ArrayList(u8).init(allocator); + defer help_text.deinit(); + inline for (@typeInfo(std.Target.ObjectFormat).Enum.fields) |field| { + help_text.writer().print(" {s}\n", .{field.name}) catch + // TODO change this back to `break :help` + // this working around a stage1 bug. + //break :help; + @panic("out of memory"); + } + std.log.info("available object formats:\n{s}", .{help_text.items}); + } + fatal("unknown object format: '{s}'", .{opts.object_format.?}); }, else => |e| return e, }; @@ -3360,7 +3353,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void // If a .pdb file is part of the expected output, we must also copy // it into place here. - const is_coff = comp.bin_file.options.object_format == .coff; + const is_coff = comp.bin_file.options.target.ofmt == .coff; const have_pdb = is_coff and !comp.bin_file.options.strip; if (have_pdb) { // Replace `.out` or `.exe` with `.pdb` on both the source and destination diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 7010e736dc04..d4a09f79687c 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -10082,6 +10082,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " .cpu = cpu,\n" " .os = os,\n" " .abi = abi,\n" + " .ofmt = object_format,\n" "};\n" ); From cee82c7ce4fb8beb39042f9dba16a1a391803fa4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Aug 2022 20:34:36 -0700 Subject: [PATCH 6/8] improved ABI alignment/size for >= 128-bit integers * riscv64: adjust alignment and size of 128-bit integers. * take ofmt=c into account for ABI alignment of 128-bit integers and structs. * Type: make packed struct support intInfo * fix f80 alignment for i386-windows-msvc --- lib/std/target.zig | 9 +++++--- src/Module.zig | 30 +++++++++++++++++---------- src/type.zig | 16 ++++++++++++-- test/behavior/align.zig | 46 +++++++++++++++++++++++++++-------------- 4 files changed, 69 insertions(+), 32 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index 00553bb52079..64f9f9780961 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1808,20 +1808,23 @@ pub const Target = struct { // 1. Different machine code instruction when loading into SIMD register. // 2. The C ABI wants 16 for extern structs. // 3. 16-byte cmpxchg needs 16-byte alignment. - // Same logic for riscv64, powerpc64, mips64, sparc64. + // Same logic for powerpc64, mips64, sparc64. .x86_64, - .riscv64, .powerpc64, .powerpc64le, .mips64, .mips64el, .sparc64, - => 8, + => return switch (target.ofmt) { + .c => 16, + else => 8, + }, // Even LLVMABIAlignmentOfType(i128) agrees on these targets. .aarch64, .aarch64_be, .aarch64_32, + .riscv64, .bpfel, .bpfeb, .nvptx, diff --git a/src/Module.zig b/src/Module.zig index 6d2180e8e747..3ae61c264fea 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -948,20 +948,28 @@ pub const Struct = struct { switch (layout) { .Packed => return 0, - .Auto => return field.ty.abiAlignment(target), - .Extern => { - // This logic is duplicated in Type.abiAlignmentAdvanced. - const ty_abi_align = field.ty.abiAlignment(target); - - if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { - // The C ABI requires 128 bit integer fields of structs - // to be 16-bytes aligned. - return @maximum(ty_abi_align, 16); + .Auto => { + if (target.ofmt == .c) { + return alignmentExtern(field, target); + } else { + return field.ty.abiAlignment(target); } - - return ty_abi_align; }, + .Extern => return alignmentExtern(field, target), + } + } + + pub fn alignmentExtern(field: Field, target: Target) u32 { + // This logic is duplicated in Type.abiAlignmentAdvanced. + const ty_abi_align = field.ty.abiAlignment(target); + + if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { + // The C ABI requires 128 bit integer fields of structs + // to be 16-bytes aligned. + return @maximum(ty_abi_align, 16); } + + return ty_abi_align; } }; diff --git a/src/type.zig b/src/type.zig index fb2ca1e3fcb8..6a66fb9d700c 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3019,7 +3019,7 @@ pub const Type = extern union { big_align = @maximum(big_align, field_align); // This logic is duplicated in Module.Struct.Field.alignment. - if (struct_obj.layout == .Extern) { + if (struct_obj.layout == .Extern or target.ofmt == .c) { if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { // The C ABI requires 128 bit integer fields of structs // to be 16-bytes aligned. @@ -3348,7 +3348,13 @@ pub const Type = extern union { .f128 => return AbiSizeAdvanced{ .scalar = 16 }, .f80 => switch (target.cpu.arch) { - .i386 => return AbiSizeAdvanced{ .scalar = 12 }, + .i386 => switch (target.os.tag) { + .windows => switch (target.abi) { + .msvc => return AbiSizeAdvanced{ .scalar = 16 }, + else => return AbiSizeAdvanced{ .scalar = 12 }, + }, + else => return AbiSizeAdvanced{ .scalar = 12 }, + }, .x86_64 => return AbiSizeAdvanced{ .scalar = 16 }, else => { var payload: Payload.Bits = .{ @@ -4559,6 +4565,12 @@ pub const Type = extern union { .vector => ty = ty.castTag(.vector).?.data.elem_type, + .@"struct" => { + const struct_obj = ty.castTag(.@"struct").?.data; + assert(struct_obj.layout == .Packed); + ty = struct_obj.backing_int_ty; + }, + else => unreachable, }; } diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 4a824bc9cf48..ad857fb9c2e7 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" { .a_align = 8, .a_size = 16, - .b_align = 8, - .b_size = 24, + .b_align = 16, + .b_size = 32, .u128_align = 8, .u128_size = 16, @@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" { .a_align = 8, .a_size = 16, - .b_align = 8, - .b_size = 24, + .b_align = 16, + .b_size = 32, .u128_align = 8, .u128_size = 16, @@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" { .a_align = 4, .a_size = 16, - .b_align = 4, - .b_size = 20, + .b_align = 16, + .b_size = 32, .u128_align = 4, .u128_size = 16, @@ -140,25 +140,39 @@ test "alignment and size of structs with 128-bit fields" { .mips64el, .powerpc64, .powerpc64le, - .riscv64, .sparc64, .x86_64, - => .{ - .a_align = 8, - .a_size = 16, + => switch (builtin.object_format) { + .c => .{ + .a_align = 16, + .a_size = 16, - .b_align = 16, - .b_size = 32, + .b_align = 16, + .b_size = 32, - .u128_align = 8, - .u128_size = 16, - .u129_align = 8, - .u129_size = 24, + .u128_align = 16, + .u128_size = 16, + .u129_align = 16, + .u129_size = 32, + }, + else => .{ + .a_align = 8, + .a_size = 16, + + .b_align = 16, + .b_size = 32, + + .u128_align = 8, + .u128_size = 16, + .u129_align = 8, + .u129_size = 24, + }, }, .aarch64, .aarch64_be, .aarch64_32, + .riscv64, .bpfel, .bpfeb, .nvptx, From 5e989fcb679215a6357dd35b5b8903293f963846 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Aug 2022 22:02:10 -0700 Subject: [PATCH 7/8] stage2: pointers to comptime-only types are comptime-only This is a partial revert of c5ba941b77fbdb06841f28142420c6786f2a4d0c. --- src/type.zig | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/type.zig b/src/type.zig index 6a66fb9d700c..f6afa33df16d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2374,6 +2374,10 @@ pub const Type = extern union { .error_union, .error_set, .error_set_merged, + => return true, + + // Pointers to zero-bit types still have a runtime address; however, pointers + // to comptime-only types do not, with the exception of function pointers. .anyframe_T, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -2386,7 +2390,17 @@ pub const Type = extern union { .const_slice, .mut_slice, .pointer, - => return true, + => { + if (ignore_comptime_only) { + return true; + } else if (ty.childType().zigTypeTag() == .Fn) { + return true; + } else if (sema_kit) |sk| { + return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); + } else { + return !comptimeOnly(ty); + } + }, // These are false because they are comptime-only types. .single_const_pointer_to_comptime_int, From 150786e83c705a34e16f031b7848a440946b2ef9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Aug 2022 22:02:55 -0700 Subject: [PATCH 8/8] test harness: fix handling of object format Follow-up to b975f7a56fec9e0e7aca9832282bc772c743d731. --- src/test.zig | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test.zig b/src/test.zig index 266b4181e011..a8567f24928b 100644 --- a/src/test.zig +++ b/src/test.zig @@ -606,7 +606,6 @@ pub const TestContext = struct { output_mode: std.builtin.OutputMode, optimize_mode: std.builtin.Mode = .Debug, updates: std.ArrayList(Update), - object_format: ?std.Target.ObjectFormat = null, emit_h: bool = false, is_test: bool = false, expect_exact: bool = false, @@ -782,12 +781,13 @@ pub const TestContext = struct { pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch @panic("out of memory"); + var target_adjusted = target; + target_adjusted.ofmt = std.Target.ObjectFormat.c; ctx.cases.append(Case{ .name = prefixed_name, - .target = target, + .target = target_adjusted, .updates = std.ArrayList(Update).init(ctx.cases.allocator), .output_mode = .Exe, - .object_format = .c, .files = std.ArrayList(File).init(ctx.arena), }) catch @panic("out of memory"); return &ctx.cases.items[ctx.cases.items.len - 1]; @@ -851,12 +851,13 @@ pub const TestContext = struct { /// Adds a test case for Zig or ZIR input, producing C code. pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case { + var target_adjusted = target; + target_adjusted.ofmt = std.Target.ObjectFormat.c; ctx.cases.append(Case{ .name = name, - .target = target, + .target = target_adjusted, .updates = std.ArrayList(Update).init(ctx.cases.allocator), .output_mode = .Obj, - .object_format = .c, .files = std.ArrayList(File).init(ctx.arena), }) catch @panic("out of memory"); return &ctx.cases.items[ctx.cases.items.len - 1]; @@ -1501,7 +1502,6 @@ pub const TestContext = struct { .root_name = "test_case", .target = target, .output_mode = case.output_mode, - .object_format = case.object_format, }); const emit_directory: Compilation.Directory = .{ @@ -1537,7 +1537,6 @@ pub const TestContext = struct { .emit_h = emit_h, .main_pkg = &main_pkg, .keep_source_files_loaded = true, - .object_format = case.object_format, .is_native_os = case.target.isNativeOs(), .is_native_abi = case.target.isNativeAbi(), .dynamic_linker = target_info.dynamic_linker.get(), @@ -1782,7 +1781,7 @@ pub const TestContext = struct { ".." ++ ss ++ "{s}" ++ ss ++ "{s}", .{ &tmp.sub_path, bin_name }, ); - if (case.object_format != null and case.object_format.? == .c) { + if (case.target.ofmt != null and case.target.ofmt.? == .c) { if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) { // We wouldn't be able to run the compiled C code. continue :update; // Pass test.