llvm: fix various crashes

This commit is contained in:
Jacob Young 2023-07-18 03:08:15 -04:00
parent 9c4d5e64b4
commit 9dd7a9eb02
3 changed files with 262 additions and 87 deletions

View File

@ -1910,12 +1910,37 @@ pub const Target = struct {
pub fn stackAlignment(target: Target) u16 {
return switch (target.cpu.arch) {
.amdgcn => 4,
.x86 => switch (target.os.tag) {
.windows => 4,
else => 16,
},
.arm, .armeb, .mips, .mipsel => 8,
.aarch64, .aarch64_be, .powerpc64, .powerpc64le, .riscv64, .x86_64, .wasm32, .wasm64 => 16,
.arm,
.armeb,
.thumb,
.thumbeb,
.mips,
.mipsel,
.sparc,
.sparcel,
=> 8,
.aarch64,
.aarch64_be,
.aarch64_32,
.bpfeb,
.bpfel,
.mips64,
.mips64el,
.powerpc64,
.powerpc64le,
.riscv32,
.riscv64,
.sparc64,
.x86_64,
.ve,
.wasm32,
.wasm64,
=> 16,
else => @divExact(target.ptrBitWidth(), 8),
};
}

View File

@ -341,34 +341,40 @@ const DataLayoutBuilder = struct {
writer: anytype,
) @TypeOf(writer).Error!void {
const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows;
try writer.print("{c}-m:{c}", .{
@as(u8, switch (self.target.cpu.arch.endian()) {
.Little => 'e',
.Big => 'E',
}),
@as(u8, if (self.target.cpu.arch.isMIPS())
'm' // Mips mangling: Private symbols get a $ prefix.
else switch (self.target.ofmt) {
.elf => 'e', // ELF mangling: Private symbols get a `.L` prefix.
//.goff => 'l', // GOFF mangling: Private symbols get a `@` prefix.
.macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
// Other symbols get a `_` prefix.
.coff => switch (self.target.os.tag) {
.windows => switch (self.target.cpu.arch) {
.x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual prefix.
// Regular C symbols get a `_` prefix. Functions with `__stdcall`, `__fastcall`,
// and `__vectorcall` have custom mangling that appends `@N` where N is the
// number of bytes used to pass parameters. C++ symbols starting with `?` are
// not mangled in any way.
else => 'w', // Windows COFF mangling: Similar to x, except that normal C
// symbols do not receive a `_` prefix.
try writer.writeByte(switch (self.target.cpu.arch.endian()) {
.Little => 'e',
.Big => 'E',
});
switch (self.target.cpu.arch) {
.amdgcn,
.nvptx,
.nvptx64,
=> {},
.avr => try writer.writeAll("-P1"),
else => try writer.print("-m:{c}", .{@as(u8, switch (self.target.cpu.arch) {
.mips, .mipsel => 'm', // Mips mangling: Private symbols get a $ prefix.
else => switch (self.target.ofmt) {
.elf => 'e', // ELF mangling: Private symbols get a `.L` prefix.
//.goff => 'l', // GOFF mangling: Private symbols get a `@` prefix.
.macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
// Other symbols get a `_` prefix.
.coff => switch (self.target.os.tag) {
.windows => switch (self.target.cpu.arch) {
.x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
// prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
//`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
// where N is the number of bytes used to pass parameters. C++ symbols
// starting with `?` are not mangled in any way.
else => 'w', // Windows COFF mangling: Similar to x, except that normal C
// symbols do not receive a `_` prefix.
},
else => 'e',
},
//.xcoff => 'a', // XCOFF mangling: Private symbols get a `L..` prefix.
else => 'e',
},
//.xcoff => 'a', // XCOFF mangling: Private symbols get a `L..` prefix.
else => 'e',
}),
});
})}),
}
var any_non_integral = false;
const ptr_bit_width = self.target.ptrBitWidth();
var default_info = struct { size: u16, abi: u16, pref: u16, idx: u16 }{
@ -399,66 +405,134 @@ const DataLayoutBuilder = struct {
.pref = pref,
.idx = idx,
};
if (self.target.cpu.arch == .aarch64_32) continue;
if (!info.force_in_data_layout and matches_default and
self.target.cpu.arch != .riscv64 and !is_aarch64_windows) continue;
self.target.cpu.arch != .riscv64 and !is_aarch64_windows and
self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;
try writer.writeAll("-p");
if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});
try writer.print(":{d}:{d}", .{ size, abi });
if (pref != abi or idx != size) {
if (pref != abi or idx != size or self.target.cpu.arch == .hexagon) {
try writer.print(":{d}", .{pref});
if (idx != size) try writer.print(":{d}", .{idx});
}
}
if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
try writer.writeAll("-Fi8"); // for thumb interwork
try self.typeAlignment(.integer, 8, 8, 8, false, writer);
try self.typeAlignment(.integer, 16, 16, 16, false, writer);
try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
try self.typeAlignment(.integer, 64, 32, 64, false, writer);
try self.typeAlignment(.integer, 128, 32, 64, false, writer);
if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
try self.typeAlignment(.float, 32, 32, 32, false, writer);
try self.typeAlignment(.float, 64, 64, 64, false, writer);
if (backendSupportsF80(self.target)) try self.typeAlignment(.float, 80, 0, 0, false, writer);
try self.typeAlignment(.float, 128, 128, 128, false, writer);
try self.typeAlignment(.vector, 64, 64, 64, false, writer);
try self.typeAlignment(.vector, 128, 128, 128, false, writer);
if (self.target.os.tag != .windows) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
if (self.target.cpu.arch != .hexagon) {
if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);
try self.typeAlignment(.integer, 8, 8, 8, false, writer);
try self.typeAlignment(.integer, 16, 16, 16, false, writer);
try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
try self.typeAlignment(.integer, 64, 32, 64, false, writer);
try self.typeAlignment(.integer, 128, 32, 64, false, writer);
if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
try self.typeAlignment(.float, 32, 32, 32, false, writer);
try self.typeAlignment(.float, 64, 64, 64, false, writer);
if (backendSupportsF80(self.target)) try self.typeAlignment(.float, 80, 0, 0, false, writer);
try self.typeAlignment(.float, 128, 128, 128, false, writer);
}
switch (self.target.cpu.arch) {
.amdgcn => {
try self.typeAlignment(.vector, 16, 16, 16, false, writer);
try self.typeAlignment(.vector, 24, 32, 32, false, writer);
try self.typeAlignment(.vector, 32, 32, 32, false, writer);
try self.typeAlignment(.vector, 48, 64, 64, false, writer);
try self.typeAlignment(.vector, 96, 128, 128, false, writer);
try self.typeAlignment(.vector, 192, 256, 256, false, writer);
try self.typeAlignment(.vector, 256, 256, 256, false, writer);
try self.typeAlignment(.vector, 512, 512, 512, false, writer);
try self.typeAlignment(.vector, 1024, 1024, 1024, false, writer);
try self.typeAlignment(.vector, 2048, 2048, 2048, false, writer);
},
.ve => {},
else => {
try self.typeAlignment(.vector, 16, 32, 32, false, writer);
try self.typeAlignment(.vector, 32, 32, 32, false, writer);
try self.typeAlignment(.vector, 64, 64, 64, false, writer);
try self.typeAlignment(.vector, 128, 128, 128, true, writer);
},
}
if (self.target.os.tag != .windows and self.target.cpu.arch != .avr)
try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
for (@as([]const u24, switch (self.target.cpu.arch) {
.aarch64_32,
.avr => &.{8},
.msp430 => &.{ 8, 16 },
.arm,
.armeb,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.riscv32,
.sparc,
.sparcel,
.thumb,
.thumbeb,
.riscv32,
=> &.{32},
.aarch64,
.aarch64_be,
.aarch64_32,
.amdgcn,
.bpfeb,
.bpfel,
.mips64,
.mips64el,
.powerpc64,
.powerpc64le,
.riscv64,
.s390x,
.sparc64,
.ve,
.wasm32,
.wasm64,
=> &.{ 32, 64 },
.hexagon => &.{ 16, 32 },
.x86 => &.{ 8, 16, 32 },
.nvptx,
.nvptx64,
=> &.{ 16, 32, 64 },
.x86_64 => &.{ 8, 16, 32, 64 },
else => &.{},
}), 0..) |natural, index| switch (index) {
0 => try writer.print("-n{d}", .{natural}),
else => try writer.print(":{d}", .{natural}),
};
if (self.target.os.tag == .windows) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
if (self.target.cpu.arch == .hexagon) {
try self.typeAlignment(.integer, 64, 64, 64, true, writer);
try self.typeAlignment(.integer, 32, 32, 32, true, writer);
try self.typeAlignment(.integer, 16, 16, 16, true, writer);
try self.typeAlignment(.integer, 1, 8, 8, true, writer);
try self.typeAlignment(.float, 32, 32, 32, true, writer);
try self.typeAlignment(.float, 64, 64, 64, true, writer);
}
if (self.target.os.tag == .windows or self.target.cpu.arch == .avr)
try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
const stack_abi = self.target.stackAlignment() * 8;
if (self.target.os.tag == .windows or stack_abi != ptr_bit_width)
if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or
stack_abi != ptr_bit_width)
try writer.print("-S{d}", .{stack_abi});
try self.typeAlignment(.vector, 256, 128, 128, true, writer);
try self.typeAlignment(.vector, 512, 128, 128, true, writer);
switch (self.target.cpu.arch) {
.hexagon, .ve => {
try self.typeAlignment(.vector, 32, 128, 128, true, writer);
try self.typeAlignment(.vector, 64, 128, 128, true, writer);
try self.typeAlignment(.vector, 128, 128, 128, true, writer);
},
else => {},
}
if (self.target.cpu.arch != .amdgcn) {
try self.typeAlignment(.vector, 256, 128, 128, true, writer);
try self.typeAlignment(.vector, 512, 128, 128, true, writer);
try self.typeAlignment(.vector, 1024, 128, 128, true, writer);
try self.typeAlignment(.vector, 2048, 128, 128, true, writer);
try self.typeAlignment(.vector, 4096, 128, 128, true, writer);
try self.typeAlignment(.vector, 8192, 128, 128, true, writer);
try self.typeAlignment(.vector, 16384, 128, 128, true, writer);
}
const alloca_addr_space = llvmAllocaAddressSpace(self.target);
if (alloca_addr_space != .default) try writer.print("-A{d}", .{@intFromEnum(alloca_addr_space)});
const global_addr_space = llvmDefaultGlobalAddressSpace(self.target);
if (global_addr_space != .default) try writer.print("-G{d}", .{@intFromEnum(global_addr_space)});
if (any_non_integral) {
try writer.writeAll("-ni");
for (addr_space_info) |info| if (info.non_integral)
@ -472,11 +546,13 @@ const DataLayoutBuilder = struct {
size: u24,
default_abi: u24,
default_pref: u24,
force_pref: bool,
default_force_pref: bool,
writer: anytype,
) @TypeOf(writer).Error!void {
var abi = default_abi;
var pref = default_pref;
var force_abi = false;
var force_pref = default_force_pref;
if (kind == .float and size == 80) {
abi = 128;
pref = 128;
@ -493,21 +569,45 @@ const DataLayoutBuilder = struct {
}
switch (kind) {
.integer => {
if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
abi = @min(abi, self.target.maxIntAlignment() * 8);
switch (self.target.os.tag) {
.linux => switch (self.target.cpu.arch) {
.aarch64, .aarch64_be, .mips, .mipsel => pref = @max(pref, 32),
.aarch64,
.aarch64_be,
.aarch64_32,
.mips,
.mipsel,
=> pref = @max(pref, 32),
else => {},
},
else => {},
}
switch (self.target.cpu.arch) {
.aarch64, .aarch64_be, .riscv64 => switch (size) {
128 => {
abi = size;
pref = size;
},
else => {},
.aarch64,
.aarch64_be,
.aarch64_32,
.bpfeb,
.bpfel,
.nvptx,
.nvptx64,
.riscv64,
=> if (size == 128) {
abi = size;
pref = size;
},
.hexagon => force_abi = true,
.mips64,
.mips64el,
=> if (size <= 32) {
pref = 32;
},
.s390x => if (size <= 16) {
pref = 16;
},
.ve => if (size == 64) {
abi = size;
pref = size;
},
else => {},
}
@ -517,18 +617,66 @@ const DataLayoutBuilder = struct {
128 => abi = 64,
else => {},
}
} else if (self.target.cpu.arch.isPPC64()) {
} else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or
(self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))
{
force_abi = true;
abi = size;
pref = size;
} else if (self.target.cpu.arch == .amdgcn and size <= 2048) {
force_abi = true;
} else if (self.target.cpu.arch == .hexagon and
((size >= 32 and size <= 64) or (size >= 512 and size <= 2048)))
{
abi = size;
pref = size;
force_pref = true;
} else if (self.target.cpu.arch == .s390x and size == 128) {
abi = 64;
pref = 64;
force_pref = false;
} else if (self.target.cpu.arch == .ve and (size >= 64 and size <= 16384)) {
abi = 64;
pref = 64;
force_abi = true;
force_pref = true;
},
.float => switch (self.target.cpu.arch) {
.avr, .msp430, .sparc64 => if (size != 32 and size != 64) return,
.hexagon => if (size == 32 or size == 64) {
force_abi = true;
},
.aarch64_32 => if (size == 128) {
abi = size;
pref = size;
},
.ve => if (size == 64) {
abi = size;
pref = size;
},
else => {},
},
.float => {},
.aggregate => if (self.target.os.tag == .windows or
self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
{
pref = @min(pref, self.target.ptrBitWidth());
} else if (self.target.cpu.arch == .hexagon) {
abi = 0;
pref = 0;
} else if (self.target.cpu.arch == .s390x) {
abi = 8;
pref = 16;
} else if (self.target.cpu.arch == .msp430) {
abi = 8;
pref = 8;
},
}
if (abi == default_abi and pref == default_pref) return;
if (kind != .vector and self.target.cpu.arch == .avr) {
force_abi = true;
abi = 8;
pref = 8;
}
if (!force_abi and abi == default_abi and pref == default_pref) return;
try writer.print("-{c}", .{@tagName(kind)[0]});
if (size != 0) try writer.print("{d}", .{size});
try writer.print(":{d}", .{abi});
@ -5096,12 +5244,15 @@ pub const FuncGen = struct {
// In this case the function return type is honoring the calling convention by having
// a different LLVM type than the usual one. We solve this here at the callsite
// by using our canonical type, then loading it if necessary.
const rp = try self.buildAlloca(llvm_ret_ty, .default);
_ = try self.wip.store(.normal, call, rp, .default);
const alignment = Builder.Alignment.fromByteUnits(
o.target_data.abiAlignmentOfType(abi_ret_ty.toLlvm(&o.builder)),
);
const rp = try self.buildAlloca(llvm_ret_ty, alignment);
_ = try self.wip.store(.normal, call, rp, alignment);
return if (isByRef(return_type, mod))
rp
else
try self.wip.load(.normal, llvm_ret_ty, rp, .default, "");
try self.wip.load(.normal, llvm_ret_ty, rp, alignment, "");
}
if (isByRef(return_type, mod)) {
@ -10923,23 +11074,26 @@ fn llvmAddrSpaceInfo(target: std.Target) []const AddrSpaceInfo {
.{ .zig = .local, .llvm = Builder.AddrSpace.nvptx.local },
},
.amdgcn => &.{
.{ .zig = .generic, .llvm = Builder.AddrSpace.amdgpu.flat },
.{ .zig = .global, .llvm = Builder.AddrSpace.amdgpu.global },
.{ .zig = .constant, .llvm = Builder.AddrSpace.amdgpu.constant },
.{ .zig = .shared, .llvm = Builder.AddrSpace.amdgpu.local },
.{ .zig = .local, .llvm = Builder.AddrSpace.amdgpu.private },
.{ .zig = .generic, .llvm = Builder.AddrSpace.amdgpu.flat, .force_in_data_layout = true },
.{ .zig = .global, .llvm = Builder.AddrSpace.amdgpu.global, .force_in_data_layout = true },
.{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.region, .size = 32, .abi = 32 },
.{ .zig = .shared, .llvm = Builder.AddrSpace.amdgpu.local, .size = 32, .abi = 32 },
.{ .zig = .constant, .llvm = Builder.AddrSpace.amdgpu.constant, .force_in_data_layout = true },
.{ .zig = .local, .llvm = Builder.AddrSpace.amdgpu.private, .size = 32, .abi = 32 },
.{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.constant_32bit, .size = 32, .abi = 32 },
.{ .zig = null, .llvm = Builder.AddrSpace.amdgpu.buffer_fat_pointer, .non_integral = true },
},
.avr => &.{
.{ .zig = .generic, .llvm = .default },
.{ .zig = .flash, .llvm = Builder.AddrSpace.avr.flash },
.{ .zig = .flash1, .llvm = Builder.AddrSpace.avr.flash1 },
.{ .zig = .flash2, .llvm = Builder.AddrSpace.avr.flash2 },
.{ .zig = .flash3, .llvm = Builder.AddrSpace.avr.flash3 },
.{ .zig = .flash4, .llvm = Builder.AddrSpace.avr.flash4 },
.{ .zig = .flash5, .llvm = Builder.AddrSpace.avr.flash5 },
.{ .zig = .generic, .llvm = .default, .abi = 8 },
.{ .zig = .flash, .llvm = Builder.AddrSpace.avr.flash, .abi = 8 },
.{ .zig = .flash1, .llvm = Builder.AddrSpace.avr.flash1, .abi = 8 },
.{ .zig = .flash2, .llvm = Builder.AddrSpace.avr.flash2, .abi = 8 },
.{ .zig = .flash3, .llvm = Builder.AddrSpace.avr.flash3, .abi = 8 },
.{ .zig = .flash4, .llvm = Builder.AddrSpace.avr.flash4, .abi = 8 },
.{ .zig = .flash5, .llvm = Builder.AddrSpace.avr.flash5, .abi = 8 },
},
.wasm32, .wasm64 => &.{
.{ .zig = .generic, .llvm = .default },
.{ .zig = .generic, .llvm = .default, .force_in_data_layout = true },
.{ .zig = null, .llvm = Builder.AddrSpace.wasm.variable, .non_integral = true },
.{ .zig = null, .llvm = Builder.AddrSpace.wasm.externref, .non_integral = true, .size = 8, .abi = 8 },
.{ .zig = null, .llvm = Builder.AddrSpace.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 },

View File

@ -2789,10 +2789,6 @@ pub const WipFunction = struct {
name: []const u8,
) Allocator.Error!Value {
assert(ptr.typeOfWip(self).isPointer(self.builder));
const final_scope = switch (ordering) {
.none => .system,
else => scope,
};
try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
const instruction = try self.addInst(name, .{
.tag = switch (ordering) {
@ -2808,7 +2804,10 @@ pub const WipFunction = struct {
.data = self.addExtraAssumeCapacity(Instruction.Load{
.type = ty,
.ptr = ptr,
.info = .{ .scope = final_scope, .ordering = ordering, .alignment = alignment },
.info = .{ .scope = switch (ordering) {
.none => .system,
else => scope,
}, .ordering = ordering, .alignment = alignment },
}),
});
if (self.builder.useLibLlvm()) {
@ -2817,7 +2816,6 @@ pub const WipFunction = struct {
ptr.toLlvm(self),
instruction.llvmName(self),
);
if (final_scope == .singlethread) llvm_instruction.setAtomicSingleThread(.True);
if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
@ -2845,10 +2843,6 @@ pub const WipFunction = struct {
alignment: Alignment,
) Allocator.Error!Instruction.Index {
assert(ptr.typeOfWip(self).isPointer(self.builder));
const final_scope = switch (ordering) {
.none => .system,
else => scope,
};
try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
const instruction = try self.addInst(null, .{
.tag = switch (ordering) {
@ -2864,7 +2858,10 @@ pub const WipFunction = struct {
.data = self.addExtraAssumeCapacity(Instruction.Store{
.val = val,
.ptr = ptr,
.info = .{ .scope = final_scope, .ordering = ordering, .alignment = alignment },
.info = .{ .scope = switch (ordering) {
.none => .system,
else => scope,
}, .ordering = ordering, .alignment = alignment },
}),
});
if (self.builder.useLibLlvm()) {
@ -2873,7 +2870,6 @@ pub const WipFunction = struct {
.normal => {},
.@"volatile" => llvm_instruction.setVolatile(.True),
}
if (final_scope == .singlethread) llvm_instruction.setAtomicSingleThread(.True);
if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
self.llvm.instructions.appendAssumeCapacity(llvm_instruction);