authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-01 17:14:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-08 19:37:29-07:00
log708894cf9903bab2e9b0dde0b609a6cc7cc55ffd
treea161dbfb600fef3c647a038e4dcbd142e2389f76
parent6730b366a059a83d64f66644bf49d69cb31a6a08

add a debug subcommand for printing LLVM integer type alignment

Useful when debugging why upgrading from LLVM 17 to 18 caused C ABI regressions. Turns out LLVM 18 does the following insane thing: ```diff -[nix-shell:~/dev/zig/build-llvm17]$ stage4/bin/zig llvm-ints i386-linux-musl +[nix-shell:~/src/zig/build-llvm18]$ stage4/bin/zig llvm-ints i386-linux-musl LLVMABIAlignmentOfType(i1) == 1 LLVMABIAlignmentOfType(i8) == 1 LLVMABIAlignmentOfType(i16) == 2 LLVMABIAlignmentOfType(i32) == 4 LLVMABIAlignmentOfType(i64) == 4 -LLVMABIAlignmentOfType(i128) == 4 -LLVMABIAlignmentOfType(i256) == 4 +LLVMABIAlignmentOfType(i128) == 16 +LLVMABIAlignmentOfType(i256) == 16 ```

2 files changed, 56 insertions(+), 0 deletions(-)

src/codegen/llvm/bindings.zig+11
...@@ -43,6 +43,9 @@ pub const Context = opaque {...@@ -43,6 +43,9 @@ pub const Context = opaque {
4343
44 pub const getBrokenDebugInfo = ZigLLVMGetBrokenDebugInfo;44 pub const getBrokenDebugInfo = ZigLLVMGetBrokenDebugInfo;
45 extern fn ZigLLVMGetBrokenDebugInfo(C: *Context) bool;45 extern fn ZigLLVMGetBrokenDebugInfo(C: *Context) bool;
46
47 pub const intType = LLVMIntTypeInContext;
48 extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) *Type;
46};49};
4750
48pub const Module = opaque {51pub const Module = opaque {
...@@ -96,13 +99,21 @@ pub const TargetMachine = opaque {...@@ -96,13 +99,21 @@ pub const TargetMachine = opaque {
96 llvm_ir_filename: ?[*:0]const u8,99 llvm_ir_filename: ?[*:0]const u8,
97 bitcode_filename: ?[*:0]const u8,100 bitcode_filename: ?[*:0]const u8,
98 ) bool;101 ) bool;
102
103 pub const createTargetDataLayout = LLVMCreateTargetDataLayout;
104 extern fn LLVMCreateTargetDataLayout(*TargetMachine) *TargetData;
99};105};
100106
101pub const TargetData = opaque {107pub const TargetData = opaque {
102 pub const dispose = LLVMDisposeTargetData;108 pub const dispose = LLVMDisposeTargetData;
103 extern fn LLVMDisposeTargetData(*TargetData) void;109 extern fn LLVMDisposeTargetData(*TargetData) void;
110
111 pub const abiAlignmentOfType = LLVMABIAlignmentOfType;
112 extern fn LLVMABIAlignmentOfType(TD: *TargetData, Ty: *Type) c_uint;
104};113};
105114
115pub const Type = opaque {};
116
106pub const CodeModel = enum(c_int) {117pub const CodeModel = enum(c_int) {
107 Default,118 Default,
108 JITDefault,119 JITDefault,
src/main.zig+45
...@@ -118,6 +118,7 @@ const debug_usage = normal_usage ++...@@ -118,6 +118,7 @@ const debug_usage = normal_usage ++
118 \\ changelist Compute mappings from old ZIR to new ZIR118 \\ changelist Compute mappings from old ZIR to new ZIR
119 \\ dump-zir Dump a file containing cached ZIR119 \\ dump-zir Dump a file containing cached ZIR
120 \\ detect-cpu Compare Zig's CPU feature detection vs LLVM120 \\ detect-cpu Compare Zig's CPU feature detection vs LLVM
121 \\ llvm-ints Dump a list of LLVMABIAlignmentOfType for all integers
121 \\122 \\
122;123;
123124
...@@ -359,6 +360,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -359,6 +360,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
359 return cmdChangelist(gpa, arena, cmd_args);360 return cmdChangelist(gpa, arena, cmd_args);
360 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {361 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
361 return cmdDumpZir(gpa, arena, cmd_args);362 return cmdDumpZir(gpa, arena, cmd_args);
363 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "llvm-ints")) {
364 return cmdDumpLlvmInts(gpa, arena, cmd_args);
362 } else {365 } else {
363 std.log.info("{s}", .{usage});366 std.log.info("{s}", .{usage});
364 fatal("unknown command: {s}", .{args[1]});367 fatal("unknown command: {s}", .{args[1]});
...@@ -6292,6 +6295,48 @@ fn printCpu(cpu: std.Target.Cpu) !void {...@@ -6292,6 +6295,48 @@ fn printCpu(cpu: std.Target.Cpu) !void {
6292 try bw.flush();6295 try bw.flush();
6293}6296}
62946297
6298fn cmdDumpLlvmInts(
6299 gpa: Allocator,
6300 arena: Allocator,
6301 args: []const []const u8,
6302) !void {
6303 _ = gpa;
6304
6305 if (!build_options.have_llvm)
6306 fatal("compiler does not use LLVM; cannot dump LLVM integer sizes", .{});
6307
6308 const triple = try arena.dupeZ(u8, args[0]);
6309
6310 const llvm = @import("codegen/llvm/bindings.zig");
6311
6312 for ([_]std.Target.Cpu.Arch{ .aarch64, .x86 }) |arch| {
6313 @import("codegen/llvm.zig").initializeLLVMTarget(arch);
6314 }
6315
6316 const target: *llvm.Target = t: {
6317 var target: *llvm.Target = undefined;
6318 var error_message: [*:0]const u8 = undefined;
6319 if (llvm.Target.getFromTriple(triple, &target, &error_message) != .False) @panic("bad");
6320 break :t target;
6321 };
6322 const tm = llvm.TargetMachine.create(target, triple, null, null, .None, .Default, .Default, false, false, .Default, null);
6323 const dl = tm.createTargetDataLayout();
6324 const context = llvm.Context.create();
6325
6326 var bw = io.bufferedWriter(io.getStdOut().writer());
6327 const stdout = bw.writer();
6328
6329 for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
6330 const int_type = context.intType(bits);
6331 const alignment = dl.abiAlignmentOfType(int_type);
6332 try stdout.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment });
6333 }
6334
6335 try bw.flush();
6336
6337 return cleanExit();
6338}
6339
6295/// This is only enabled for debug builds.6340/// This is only enabled for debug builds.
6296fn cmdDumpZir(6341fn cmdDumpZir(
6297 gpa: Allocator,6342 gpa: Allocator,