authorgravatar for gwenzek@users.noreply.github.comGuillaume Wenzek <gwenzek@users.noreply.github.com> 2022-11-20 10:14:02+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 14:33:43-07:00
log58ac0082d291fbce4125e86e1d61c9b6e8c3ce4a
treea2e544db7169c85faa3e7c01d9a4def640373a1a
parent4428e3837c0cb5fba3864cbe72cfe7cf4f94b40a

compute LLVMTypes in ParamTypeIterator (#13592)

follow up on #13376 - fixes a bug in the x86_64 C ABI. Co-authored-by: Veikka Tuominen <git@vexu.eu>

3 files changed, 77 insertions(+), 137 deletions(-)

src/arch/x86_64/abi.zig+45
......@@ -507,3 +507,48 @@ pub const RegisterClass = struct {
507507 break :blk set;
508508 };
509509};
510
511const testing = std.testing;
512const Module = @import("../../Module.zig");
513const Value = @import("../../value.zig").Value;
514const builtin = @import("builtin");
515
516fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field {
517 return .{
518 .ty = Type.initTag(tag),
519 .default_val = Value.initTag(.unreachable_value),
520 .abi_align = 0,
521 .offset = offset,
522 .is_comptime = false,
523 };
524}
525
526test "C_C_D" {
527 var fields = Module.Struct.Fields{};
528 // const C_C_D = extern struct { v1: i8, v2: i8, v3: f64 };
529 try fields.ensureTotalCapacity(testing.allocator, 3);
530 defer fields.deinit(testing.allocator);
531 fields.putAssumeCapacity("v1", _field(.i8, 0));
532 fields.putAssumeCapacity("v2", _field(.i8, 1));
533 fields.putAssumeCapacity("v3", _field(.f64, 4));
534
535 var C_C_D_struct = Module.Struct{
536 .fields = fields,
537 .namespace = undefined,
538 .owner_decl = undefined,
539 .zir_index = undefined,
540 .layout = .Extern,
541 .status = .fully_resolved,
542 .known_non_opv = true,
543 };
544 var C_C_D = Type.Payload.Struct{ .data = &C_C_D_struct };
545
546 try testing.expectEqual(
547 [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none },
548 classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .ret),
549 );
550 try testing.expectEqual(
551 [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none },
552 classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .arg),
553 );
554}
src/codegen/llvm.zig+28-125
......@@ -1049,60 +1049,20 @@ pub const Object = struct {
10491049 const aggregate = builder.buildInsertValue(partial, len_param, 1, "");
10501050 try args.append(aggregate);
10511051 },
1052 .multiple_llvm_ints => {
1052 .multiple_llvm_types => {
10531053 assert(!it.byval_attr);
1054 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
1054 const field_types = it.llvm_types_buffer[0..it.llvm_types_len];
10551055 const param_ty = fn_info.param_types[it.zig_index - 1];
10561056 const param_llvm_ty = try dg.lowerType(param_ty);
10571057 const param_alignment = param_ty.abiAlignment(target);
10581058 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1059 var field_types_buf: [8]*llvm.Type = undefined;
1060 const field_types = field_types_buf[0..llvm_ints.len];
1061 for (llvm_ints) |int_bits, i| {
1062 field_types[i] = dg.context.intType(int_bits);
1063 }
1064 const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
1065 const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
1066 for (llvm_ints) |_, field_i_usize| {
1059 const llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
1060 const casted_ptr = builder.buildBitCast(arg_ptr, llvm_ty.pointerType(0), "");
1061 for (field_types) |_, field_i_usize| {
10671062 const field_i = @intCast(c_uint, field_i_usize);
10681063 const param = llvm_func.getParam(llvm_arg_i);
10691064 llvm_arg_i += 1;
1070 const field_ptr = builder.buildStructGEP(ints_llvm_ty, casted_ptr, field_i, "");
1071 const store_inst = builder.buildStore(param, field_ptr);
1072 store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
1073 }
1074
1075 const is_by_ref = isByRef(param_ty);
1076 const loaded = if (is_by_ref) arg_ptr else l: {
1077 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1078 load_inst.setAlignment(param_alignment);
1079 break :l load_inst;
1080 };
1081 try args.append(loaded);
1082 },
1083 .multiple_llvm_float => {
1084 assert(!it.byval_attr);
1085 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
1086 const param_ty = fn_info.param_types[it.zig_index - 1];
1087 const param_llvm_ty = try dg.lowerType(param_ty);
1088 const param_alignment = param_ty.abiAlignment(target);
1089 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1090 var field_types_buf: [8]*llvm.Type = undefined;
1091 const field_types = field_types_buf[0..llvm_floats.len];
1092 for (llvm_floats) |float_bits, i| {
1093 switch (float_bits) {
1094 64 => field_types[i] = dg.context.doubleType(),
1095 80 => field_types[i] = dg.context.x86FP80Type(),
1096 else => {},
1097 }
1098 }
1099 const floats_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
1100 const casted_ptr = builder.buildBitCast(arg_ptr, floats_llvm_ty.pointerType(0), "");
1101 for (llvm_floats) |_, field_i_usize| {
1102 const field_i = @intCast(c_uint, field_i_usize);
1103 const param = llvm_func.getParam(llvm_arg_i);
1104 llvm_arg_i += 1;
1105 const field_ptr = builder.buildStructGEP(floats_llvm_ty, casted_ptr, field_i, "");
1065 const field_ptr = builder.buildStructGEP(llvm_ty, casted_ptr, field_i, "");
11061066 const store_inst = builder.buildStore(param, field_ptr);
11071067 store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
11081068 }
......@@ -2626,8 +2586,7 @@ pub const DeclGen = struct {
26262586 // No attributes needed for these.
26272587 .no_bits,
26282588 .abi_sized_int,
2629 .multiple_llvm_ints,
2630 .multiple_llvm_float,
2589 .multiple_llvm_types,
26312590 .as_u16,
26322591 .float_array,
26332592 .i32_array,
......@@ -3167,25 +3126,8 @@ pub const DeclGen = struct {
31673126 llvm_params.appendAssumeCapacity(ptr_llvm_ty);
31683127 llvm_params.appendAssumeCapacity(len_llvm_ty);
31693128 },
3170 .multiple_llvm_ints => {
3171 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
3172 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
3173 for (llvm_ints) |int_bits| {
3174 const big_int_ty = dg.context.intType(int_bits);
3175 llvm_params.appendAssumeCapacity(big_int_ty);
3176 }
3177 },
3178 .multiple_llvm_float => {
3179 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
3180 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
3181 for (llvm_ints) |float_bits| {
3182 const float_ty = switch (float_bits) {
3183 64 => dg.context.doubleType(),
3184 80 => dg.context.x86FP80Type(),
3185 else => unreachable,
3186 };
3187 llvm_params.appendAssumeCapacity(float_ty);
3188 }
3129 .multiple_llvm_types => {
3130 try llvm_params.appendSlice(it.llvm_types_buffer[0..it.llvm_types_len]);
31893131 },
31903132 .as_u16 => {
31913133 try llvm_params.append(dg.context.intType(16));
......@@ -4824,10 +4766,10 @@ pub const FuncGen = struct {
48244766 llvm_args.appendAssumeCapacity(ptr);
48254767 llvm_args.appendAssumeCapacity(len);
48264768 },
4827 .multiple_llvm_ints => {
4769 .multiple_llvm_types => {
48284770 const arg = args[it.zig_index - 1];
48294771 const param_ty = self.air.typeOf(arg);
4830 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
4772 const llvm_types = it.llvm_types_buffer[0..it.llvm_types_len];
48314773 const llvm_arg = try self.resolveInst(arg);
48324774 const is_by_ref = isByRef(param_ty);
48334775 const arg_ptr = if (is_by_ref) llvm_arg else p: {
......@@ -4837,51 +4779,13 @@ pub const FuncGen = struct {
48374779 break :p p;
48384780 };
48394781
4840 var field_types_buf: [8]*llvm.Type = undefined;
4841 const field_types = field_types_buf[0..llvm_ints.len];
4842 for (llvm_ints) |int_bits, i| {
4843 field_types[i] = self.dg.context.intType(int_bits);
4844 }
4845 const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
4846 const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
4782 const llvm_ty = self.dg.context.structType(llvm_types.ptr, @intCast(c_uint, llvm_types.len), .False);
4783 const casted_ptr = self.builder.buildBitCast(arg_ptr, llvm_ty.pointerType(0), "");
48474784 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
4848 for (llvm_ints) |_, i_usize| {
4785 for (llvm_types) |field_ty, i_usize| {
48494786 const i = @intCast(c_uint, i_usize);
4850 const field_ptr = self.builder.buildStructGEP(ints_llvm_ty, casted_ptr, i, "");
4851 const load_inst = self.builder.buildLoad(field_types[i], field_ptr, "");
4852 load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
4853 llvm_args.appendAssumeCapacity(load_inst);
4854 }
4855 },
4856 .multiple_llvm_float => {
4857 const arg = args[it.zig_index - 1];
4858 const param_ty = self.air.typeOf(arg);
4859 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
4860 const llvm_arg = try self.resolveInst(arg);
4861 const is_by_ref = isByRef(param_ty);
4862 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4863 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4864 const store_inst = self.builder.buildStore(llvm_arg, p);
4865 store_inst.setAlignment(param_ty.abiAlignment(target));
4866 break :p p;
4867 };
4868
4869 var field_types_buf: [8]*llvm.Type = undefined;
4870 const field_types = field_types_buf[0..llvm_floats.len];
4871 for (llvm_floats) |float_bits, i| {
4872 switch (float_bits) {
4873 64 => field_types[i] = self.dg.context.doubleType(),
4874 80 => field_types[i] = self.dg.context.x86FP80Type(),
4875 else => {},
4876 }
4877 }
4878 const floats_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
4879 const casted_ptr = self.builder.buildBitCast(arg_ptr, floats_llvm_ty.pointerType(0), "");
4880 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
4881 for (llvm_floats) |_, i_usize| {
4882 const i = @intCast(c_uint, i_usize);
4883 const field_ptr = self.builder.buildStructGEP(floats_llvm_ty, casted_ptr, i, "");
4884 const load_inst = self.builder.buildLoad(field_types[i], field_ptr, "");
4787 const field_ptr = self.builder.buildStructGEP(llvm_ty, casted_ptr, i, "");
4788 const load_inst = self.builder.buildLoad(field_ty, field_ptr, "");
48854789 load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
48864790 llvm_args.appendAssumeCapacity(load_inst);
48874791 }
......@@ -10473,7 +10377,7 @@ const ParamTypeIterator = struct {
1047310377 llvm_index: u32,
1047410378 target: std.Target,
1047510379 llvm_types_len: u32,
10476 llvm_types_buffer: [8]u16,
10380 llvm_types_buffer: [8]*llvm.Type,
1047710381 byval_attr: bool,
1047810382
1047910383 const Lowering = union(enum) {
......@@ -10481,8 +10385,7 @@ const ParamTypeIterator = struct {
1048110385 byval,
1048210386 byref,
1048310387 abi_sized_int,
10484 multiple_llvm_ints,
10485 multiple_llvm_float,
10388 multiple_llvm_types,
1048610389 slice,
1048710390 as_u16,
1048810391 float_array: u8,
......@@ -10515,7 +10418,7 @@ const ParamTypeIterator = struct {
1051510418 it.zig_index += 1;
1051610419 return .no_bits;
1051710420 }
10518
10421 const dg = it.dg;
1051910422 switch (it.fn_info.cc) {
1052010423 .Unspecified, .Inline => {
1052110424 it.zig_index += 1;
......@@ -10584,28 +10487,28 @@ const ParamTypeIterator = struct {
1058410487 it.llvm_index += 1;
1058510488 return .byval;
1058610489 }
10587 var llvm_types_buffer: [8]u16 = undefined;
10490 var llvm_types_buffer: [8]*llvm.Type = undefined;
1058810491 var llvm_types_index: u32 = 0;
1058910492 for (classes) |class| {
1059010493 switch (class) {
1059110494 .integer => {
10592 llvm_types_buffer[llvm_types_index] = 64;
10495 llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
1059310496 llvm_types_index += 1;
1059410497 },
1059510498 .sse => {
10596 llvm_types_buffer[llvm_types_index] = 64;
10499 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
1059710500 llvm_types_index += 1;
1059810501 },
1059910502 .sseup => {
10600 llvm_types_buffer[llvm_types_index] = 64;
10503 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
1060110504 llvm_types_index += 1;
1060210505 },
1060310506 .x87 => {
10604 llvm_types_buffer[llvm_types_index] = 80;
10507 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
1060510508 llvm_types_index += 1;
1060610509 },
1060710510 .x87up => {
10608 llvm_types_buffer[llvm_types_index] = 80;
10511 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
1060910512 llvm_types_index += 1;
1061010513 },
1061110514 .complex_x87 => {
......@@ -10625,7 +10528,7 @@ const ParamTypeIterator = struct {
1062510528 it.llvm_types_len = llvm_types_index;
1062610529 it.llvm_index += llvm_types_index;
1062710530 it.zig_index += 1;
10628 return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
10531 return .multiple_llvm_types;
1062910532 },
1063010533 },
1063110534 .wasm32 => {
......@@ -10649,8 +10552,8 @@ const ParamTypeIterator = struct {
1064910552 .byval => return .byval,
1065010553 .integer => {
1065110554 it.llvm_types_len = 1;
10652 it.llvm_types_buffer[0] = 64;
10653 return .multiple_llvm_ints;
10555 it.llvm_types_buffer[0] = dg.context.intType(64);
10556 return .multiple_llvm_types;
1065410557 },
1065510558 .double_integer => return Lowering{ .i64_array = 2 },
1065610559 }
test/c_abi/main.zig+4-12
......@@ -851,8 +851,6 @@ pub inline fn expectOk(c_err: c_int) !void {
851851/// Tests for Double + Char struct
852852const DC = extern struct { v1: f64, v2: u8 };
853853test "DC: Zig passes to C" {
854 if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows)
855 return error.SkipZigTest;
856854 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
857855 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
858856 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
......@@ -866,8 +864,6 @@ test "DC: Zig returns to C" {
866864 try expectOk(c_assert_ret_DC());
867865}
868866test "DC: C passes to Zig" {
869 if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows)
870 return error.SkipZigTest;
871867 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
872868 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
873869 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
......@@ -900,8 +896,7 @@ pub export fn zig_ret_DC() DC {
900896const CFF = extern struct { v1: u8, v2: f32, v3: f32 };
901897
902898test "CFF: Zig passes to C" {
903 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
904 return error.SkipZigTest;
899 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
905900 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
906901 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
907902 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
......@@ -914,8 +909,7 @@ test "CFF: Zig returns to C" {
914909 try expectOk(c_assert_ret_CFF());
915910}
916911test "CFF: C passes to Zig" {
917 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
918 return error.SkipZigTest;
912 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
919913 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
920914 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
921915 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
......@@ -950,8 +944,7 @@ pub export fn zig_ret_CFF() CFF {
950944const PD = extern struct { v1: ?*anyopaque, v2: f64 };
951945
952946test "PD: Zig passes to C" {
953 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
954 return error.SkipZigTest;
947 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
955948 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
956949 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
957950 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
......@@ -964,8 +957,7 @@ test "PD: Zig returns to C" {
964957 try expectOk(c_assert_ret_PD());
965958}
966959test "PD: C passes to Zig" {
967 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
968 return error.SkipZigTest;
960 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
969961 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
970962 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
971963 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;