From 708894cf9903bab2e9b0dde0b609a6cc7cc55ffd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 1 May 2024 17:14:24 -0700 Subject: [PATCH] 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 ``` --- src/codegen/llvm/bindings.zig | 11 +++++++++ src/main.zig | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 0f4caab442..99a3de043e 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -43,6 +43,9 @@ pub const Context = opaque { pub const getBrokenDebugInfo = ZigLLVMGetBrokenDebugInfo; extern fn ZigLLVMGetBrokenDebugInfo(C: *Context) bool; + + pub const intType = LLVMIntTypeInContext; + extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) *Type; }; pub const Module = opaque { @@ -96,13 +99,21 @@ pub const TargetMachine = opaque { llvm_ir_filename: ?[*:0]const u8, bitcode_filename: ?[*:0]const u8, ) bool; + + pub const createTargetDataLayout = LLVMCreateTargetDataLayout; + extern fn LLVMCreateTargetDataLayout(*TargetMachine) *TargetData; }; pub const TargetData = opaque { pub const dispose = LLVMDisposeTargetData; extern fn LLVMDisposeTargetData(*TargetData) void; + + pub const abiAlignmentOfType = LLVMABIAlignmentOfType; + extern fn LLVMABIAlignmentOfType(TD: *TargetData, Ty: *Type) c_uint; }; +pub const Type = opaque {}; + pub const CodeModel = enum(c_int) { Default, JITDefault, diff --git a/src/main.zig b/src/main.zig index 0f3338025b..7e6b5d261f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -118,6 +118,7 @@ const debug_usage = normal_usage ++ \\ changelist Compute mappings from old ZIR to new ZIR \\ dump-zir Dump a file containing cached ZIR \\ detect-cpu Compare Zig's CPU feature detection vs LLVM + \\ llvm-ints Dump a list of LLVMABIAlignmentOfType for all integers \\ ; @@ -359,6 +360,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { return cmdChangelist(gpa, arena, cmd_args); } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) { return cmdDumpZir(gpa, arena, cmd_args); + } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "llvm-ints")) { + return cmdDumpLlvmInts(gpa, arena, cmd_args); } else { std.log.info("{s}", .{usage}); fatal("unknown command: {s}", .{args[1]}); @@ -6292,6 +6295,48 @@ fn printCpu(cpu: std.Target.Cpu) !void { try bw.flush(); } +fn cmdDumpLlvmInts( + gpa: Allocator, + arena: Allocator, + args: []const []const u8, +) !void { + _ = gpa; + + if (!build_options.have_llvm) + fatal("compiler does not use LLVM; cannot dump LLVM integer sizes", .{}); + + const triple = try arena.dupeZ(u8, args[0]); + + const llvm = @import("codegen/llvm/bindings.zig"); + + for ([_]std.Target.Cpu.Arch{ .aarch64, .x86 }) |arch| { + @import("codegen/llvm.zig").initializeLLVMTarget(arch); + } + + const target: *llvm.Target = t: { + var target: *llvm.Target = undefined; + var error_message: [*:0]const u8 = undefined; + if (llvm.Target.getFromTriple(triple, &target, &error_message) != .False) @panic("bad"); + break :t target; + }; + const tm = llvm.TargetMachine.create(target, triple, null, null, .None, .Default, .Default, false, false, .Default, null); + const dl = tm.createTargetDataLayout(); + const context = llvm.Context.create(); + + var bw = io.bufferedWriter(io.getStdOut().writer()); + const stdout = bw.writer(); + + for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| { + const int_type = context.intType(bits); + const alignment = dl.abiAlignmentOfType(int_type); + try stdout.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment }); + } + + try bw.flush(); + + return cleanExit(); +} + /// This is only enabled for debug builds. fn cmdDumpZir( gpa: Allocator,