Merge pull request #12145 from ziglang/fixes
More ABI size and alignment fixes
This commit is contained in:
@@ -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();
|
||||
}
|
||||
@@ -1806,24 +1803,28 @@ 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.
|
||||
// Same logic for powerpc64, mips64, sparc64.
|
||||
.x86_64,
|
||||
.riscv64,
|
||||
.powerpc64,
|
||||
.powerpc64le,
|
||||
.mips64,
|
||||
.mips64el,
|
||||
.sparc64,
|
||||
=> return switch (target.ofmt) {
|
||||
.c => 16,
|
||||
else => 8,
|
||||
},
|
||||
|
||||
// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
|
||||
.aarch64,
|
||||
.aarch64_be,
|
||||
.aarch64_32,
|
||||
.riscv64,
|
||||
.bpfel,
|
||||
.bpfeb,
|
||||
.nvptx,
|
||||
|
||||
@@ -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}),
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -935,13 +935,41 @@ 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 => {
|
||||
if (target.ofmt == .c) {
|
||||
return alignmentExtern(field, target);
|
||||
} else {
|
||||
return field.ty.abiAlignment(target);
|
||||
}
|
||||
},
|
||||
.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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -20657,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
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
11
src/link.zig
11
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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
51
src/main.zig
51
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
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
|
||||
15
src/test.zig
15
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.
|
||||
|
||||
103
src/type.zig
103
src/type.zig
@@ -2376,6 +2376,32 @@ pub const Type = extern union {
|
||||
.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,
|
||||
.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 (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,
|
||||
.void,
|
||||
@@ -2399,30 +2425,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);
|
||||
@@ -3029,6 +3031,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 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.
|
||||
big_align = @maximum(big_align, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return AbiAlignmentAdvanced{ .scalar = big_align };
|
||||
},
|
||||
@@ -3263,8 +3274,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) {
|
||||
@@ -3286,6 +3297,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",
|
||||
@@ -3329,7 +3362,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 = .{
|
||||
@@ -4540,6 +4579,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,
|
||||
};
|
||||
}
|
||||
@@ -5502,7 +5547,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;
|
||||
@@ -5609,7 +5654,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);
|
||||
|
||||
@@ -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,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
|
||||
.mips64el,
|
||||
.powerpc64,
|
||||
.powerpc64le,
|
||||
.riscv64,
|
||||
.sparc64,
|
||||
.x86_64,
|
||||
=> switch (builtin.object_format) {
|
||||
.c => .{
|
||||
.a_align = 16,
|
||||
.a_size = 16,
|
||||
|
||||
.b_align = 16,
|
||||
.b_size = 32,
|
||||
|
||||
.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,
|
||||
@@ -166,17 +193,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user