authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-09 13:23:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-11 12:14:32-07:00
log0d006afb23aa5d0308adb56d2578b4340f34231e
tree0ced413a891e61d22132f41e2661e96629cba5b6
parentbf6af1963cfb3451b3338d7488ec26f5fb7af0ed

Merge pull request #10834 from ziglang/fix-x86-i128-c-abi

stage1: fix x86 i128 C ABI for extern structs

5 files changed, 166 insertions(+), 51 deletions(-)

src/arch/x86_64/abi.zig+27-3
......@@ -18,10 +18,34 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
1818 else => return .memory,
1919 }
2020 return switch (ty.zigTypeTag()) {
21 .Int, .Bool, .Enum, .Void, .NoReturn, .ErrorSet, .Struct, .Union => .integer,
22 .Optional => if (ty.isPtrLikeOptional()) return .integer else return .memory,
21 .Pointer,
22 .Int,
23 .Bool,
24 .Enum,
25 .Void,
26 .NoReturn,
27 .ErrorSet,
28 .Struct,
29 .Union,
30 .Optional,
31 .Array,
32 .ErrorUnion,
33 .AnyFrame,
34 .Frame,
35 => .integer,
36
2337 .Float, .Vector => .sse,
24 else => unreachable,
38
39 .Type,
40 .ComptimeFloat,
41 .ComptimeInt,
42 .Undefined,
43 .Null,
44 .BoundFn,
45 .Fn,
46 .Opaque,
47 .EnumLiteral,
48 => unreachable,
2549 };
2650}
2751
src/stage1/analyze.cpp+61-16
......@@ -8255,23 +8255,53 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) {
82558255
82568256static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) {
82578257 // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
8258 switch (ty_size) {
8259 case 1:
8260 case 2:
8261 case 4:
8262 case 8:
8263 break;
8264 case 16:
8265 return (ty->id == ZigTypeIdVector) ? X64CABIClass_SSE : X64CABIClass_MEMORY;
8266 default:
8267 return X64CABIClass_MEMORY;
8268 }
82588269 switch (ty->id) {
8259 case ZigTypeIdEnum:
8270 case ZigTypeIdInvalid:
8271 case ZigTypeIdMetaType:
8272 case ZigTypeIdComptimeFloat:
8273 case ZigTypeIdComptimeInt:
8274 case ZigTypeIdNull:
8275 case ZigTypeIdUndefined:
8276 case ZigTypeIdBoundFn:
8277 case ZigTypeIdOpaque:
8278 case ZigTypeIdEnumLiteral:
8279 zig_unreachable();
8280
8281 case ZigTypeIdFn:
8282 case ZigTypeIdPointer:
82608283 case ZigTypeIdInt:
82618284 case ZigTypeIdBool:
8285 case ZigTypeIdEnum:
8286 case ZigTypeIdVoid:
8287 case ZigTypeIdUnreachable:
8288 case ZigTypeIdErrorSet:
8289 case ZigTypeIdErrorUnion:
8290 case ZigTypeIdStruct:
8291 case ZigTypeIdUnion:
8292 case ZigTypeIdOptional:
8293 case ZigTypeIdFnFrame:
8294 case ZigTypeIdAnyFrame:
82628295 return X64CABIClass_INTEGER;
8296
82638297 case ZigTypeIdFloat:
82648298 case ZigTypeIdVector:
82658299 return X64CABIClass_SSE;
8266 case ZigTypeIdStruct:
8267 case ZigTypeIdUnion: {
8268 if (ty_size <= 8)
8269 return X64CABIClass_INTEGER;
8270 return X64CABIClass_MEMORY;
8271 }
8272 default:
8300
8301 case ZigTypeIdArray:
82738302 return X64CABIClass_Unknown;
82748303 }
8304 zig_unreachable();
82758305}
82768306
82778307static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) {
......@@ -8350,17 +8380,19 @@ static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size
83508380
83518381X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
83528382 Error err;
8353
83548383 const size_t ty_size = type_size(g, ty);
8384
8385 if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) {
8386 return type_windows_abi_x86_64_class(g, ty, ty_size);
8387 }
8388
83558389 ZigType *ptr_type;
83568390 if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return X64CABIClass_Unknown;
83578391 if (ptr_type != nullptr)
83588392 return X64CABIClass_INTEGER;
83598393
8360 if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) {
8361 return type_windows_abi_x86_64_class(g, ty, ty_size);
8362 } else if (g->zig_target->arch == ZigLLVM_aarch64 ||
8363 g->zig_target->arch == ZigLLVM_aarch64_be)
8394 if (g->zig_target->arch == ZigLLVM_aarch64 ||
8395 g->zig_target->arch == ZigLLVM_aarch64_be)
83648396 {
83658397 X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size);
83668398 return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result;
......@@ -8660,14 +8692,23 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) {
86608692 if (ty->data.structure.fields[i]->offset >= 8) {
86618693 eightbyte_index = 1;
86628694 }
8663 X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields[i]->type_entry);
8695 ZigType *field_ty = ty->data.structure.fields[i]->type_entry;
8696 X64CABIClass field_class = type_c_abi_x86_64_class(g, field_ty);
86648697
86658698 if (field_class == X64CABIClass_INTEGER) {
86668699 type_classes[eightbyte_index] = X64CABIClass_INTEGER;
86678700 } else if (type_classes[eightbyte_index] == X64CABIClass_Unknown) {
86688701 type_classes[eightbyte_index] = field_class;
86698702 }
8670 type_sizes[eightbyte_index] += ty->data.structure.fields[i]->type_entry->abi_size;
8703 if (field_ty->abi_size > 8) {
8704 assert(eightbyte_index == 0);
8705 type_sizes[0] = 8;
8706 type_sizes[1] = field_ty->abi_size - 8;
8707 type_classes[1] = type_classes[0];
8708 eightbyte_index = 1;
8709 } else {
8710 type_sizes[eightbyte_index] += field_ty->abi_size;
8711 }
86718712 }
86728713
86738714 LLVMTypeRef return_elem_types[] = {
......@@ -8956,8 +8997,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
89568997 struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX;
89578998 }
89588999
8959 if (struct_type->abi_size <= 16 && (struct_type->data.structure.layout == ContainerLayoutExtern || struct_type->data.structure.layout == ContainerLayoutPacked))
9000 if (struct_type->abi_size <= 16 &&
9001 (struct_type->data.structure.layout == ContainerLayoutExtern ||
9002 struct_type->data.structure.layout == ContainerLayoutPacked))
9003 {
89609004 resolve_llvm_c_abi_type(g, struct_type);
9005 }
89619006}
89629007
89639008// This is to be used instead of void for debug info types, to avoid tripping
test/stage1/c_abi/build.zig+3
......@@ -2,15 +2,18 @@ const Builder = @import("std").build.Builder;
22
33pub fn build(b: *Builder) void {
44 const rel_opts = b.standardReleaseOptions();
5 const target = b.standardTargetOptions(.{});
56
67 const c_obj = b.addObject("cfuncs", null);
78 c_obj.addCSourceFile("cfuncs.c", &[_][]const u8{"-std=c99"});
89 c_obj.setBuildMode(rel_opts);
910 c_obj.linkSystemLibrary("c");
11 c_obj.target = target;
1012
1113 const main = b.addTest("main.zig");
1214 main.setBuildMode(rel_opts);
1315 main.addObject(c_obj);
16 main.target = target;
1417
1518 const test_step = b.step("test", "Test the program");
1619 test_step.dependOn(&main.step);
test/stage1/c_abi/cfuncs.c+26
......@@ -11,14 +11,24 @@ static void assert_or_panic(bool ok) {
1111 }
1212}
1313
14struct i128 {
15 __int128 value;
16};
17
18struct u128 {
19 unsigned __int128 value;
20};
21
1422void zig_u8(uint8_t);
1523void zig_u16(uint16_t);
1624void zig_u32(uint32_t);
1725void zig_u64(uint64_t);
26void zig_struct_u128(struct u128);
1827void zig_i8(int8_t);
1928void zig_i16(int16_t);
2029void zig_i32(int32_t);
2130void zig_i64(int64_t);
31void zig_struct_i128(struct i128);
2232void zig_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t);
2333
2434void zig_f32(float);
......@@ -130,11 +140,19 @@ void run_c_tests(void) {
130140 zig_u16(0xfffe);
131141 zig_u32(0xfffffffd);
132142 zig_u64(0xfffffffffffffffc);
143 {
144 struct u128 s = {0xfffffffffffffffc};
145 zig_struct_u128(s);
146 }
133147
134148 zig_i8(-1);
135149 zig_i16(-2);
136150 zig_i32(-3);
137151 zig_i64(-4);
152 {
153 struct i128 s = {-6};
154 zig_struct_i128(s);
155 }
138156 zig_five_integers(12, 34, 56, 78, 90);
139157
140158 zig_f32(12.34f);
......@@ -221,6 +239,10 @@ void c_u64(uint64_t x) {
221239 assert_or_panic(x == 0xfffffffffffffffcULL);
222240}
223241
242void c_struct_u128(struct u128 x) {
243 assert_or_panic(x.value == 0xfffffffffffffffcULL);
244}
245
224246void c_i8(int8_t x) {
225247 assert_or_panic(x == -1);
226248}
......@@ -237,6 +259,10 @@ void c_i64(int64_t x) {
237259 assert_or_panic(x == -4);
238260}
239261
262void c_struct_i128(struct i128 x) {
263 assert_or_panic(x.value == -6);
264}
265
240266void c_f32(float x) {
241267 assert_or_panic(x == 12.34f);
242268}
test/stage1/c_abi/main.zig+49-32
......@@ -16,20 +16,22 @@ extern fn c_u8(u8) void;
1616extern fn c_u16(u16) void;
1717extern fn c_u32(u32) void;
1818extern fn c_u64(u64) void;
19extern fn c_struct_u128(U128) void;
1920extern fn c_i8(i8) void;
2021extern fn c_i16(i16) void;
2122extern fn c_i32(i32) void;
2223extern fn c_i64(i64) void;
24extern fn c_struct_i128(I128) void;
2325
2426// On windows x64, the first 4 are passed via registers, others on the stack.
2527extern fn c_five_integers(i32, i32, i32, i32, i32) void;
2628
2729export fn zig_five_integers(a: i32, b: i32, c: i32, d: i32, e: i32) void {
28 expect(a == 12) catch @panic("test failure");
29 expect(b == 34) catch @panic("test failure");
30 expect(c == 56) catch @panic("test failure");
31 expect(d == 78) catch @panic("test failure");
32 expect(e == 90) catch @panic("test failure");
30 expect(a == 12) catch @panic("test failure: zig_five_integers 12");
31 expect(b == 34) catch @panic("test failure: zig_five_integers 34");
32 expect(c == 56) catch @panic("test failure: zig_five_integers 56");
33 expect(d == 78) catch @panic("test failure: zig_five_integers 78");
34 expect(e == 90) catch @panic("test failure: zig_five_integers 90");
3335}
3436
3537test "C ABI integers" {
......@@ -37,37 +39,52 @@ test "C ABI integers" {
3739 c_u16(0xfffe);
3840 c_u32(0xfffffffd);
3941 c_u64(0xfffffffffffffffc);
42 c_struct_u128(.{ .value = 0xfffffffffffffffc });
4043
4144 c_i8(-1);
4245 c_i16(-2);
4346 c_i32(-3);
4447 c_i64(-4);
48 c_struct_i128(.{ .value = -6 });
4549 c_five_integers(12, 34, 56, 78, 90);
4650}
4751
4852export fn zig_u8(x: u8) void {
49 expect(x == 0xff) catch @panic("test failure");
53 expect(x == 0xff) catch @panic("test failure: zig_u8");
5054}
5155export fn zig_u16(x: u16) void {
52 expect(x == 0xfffe) catch @panic("test failure");
56 expect(x == 0xfffe) catch @panic("test failure: zig_u16");
5357}
5458export fn zig_u32(x: u32) void {
55 expect(x == 0xfffffffd) catch @panic("test failure");
59 expect(x == 0xfffffffd) catch @panic("test failure: zig_u32");
5660}
5761export fn zig_u64(x: u64) void {
58 expect(x == 0xfffffffffffffffc) catch @panic("test failure");
62 expect(x == 0xfffffffffffffffc) catch @panic("test failure: zig_u64");
5963}
6064export fn zig_i8(x: i8) void {
61 expect(x == -1) catch @panic("test failure");
65 expect(x == -1) catch @panic("test failure: zig_i8");
6266}
6367export fn zig_i16(x: i16) void {
64 expect(x == -2) catch @panic("test failure");
68 expect(x == -2) catch @panic("test failure: zig_i16");
6569}
6670export fn zig_i32(x: i32) void {
67 expect(x == -3) catch @panic("test failure");
71 expect(x == -3) catch @panic("test failure: zig_i32");
6872}
6973export fn zig_i64(x: i64) void {
70 expect(x == -4) catch @panic("test failure");
74 expect(x == -4) catch @panic("test failure: zig_i64");
75}
76
77const I128 = extern struct {
78 value: i128,
79};
80const U128 = extern struct {
81 value: u128,
82};
83export fn zig_struct_i128(a: I128) void {
84 expect(a.value == -6) catch @panic("test failure: zig_struct_i128");
85}
86export fn zig_struct_u128(a: U128) void {
87 expect(a.value == 0xfffffffffffffffc) catch @panic("test failure: zig_struct_u128");
7188}
7289
7390extern fn c_f32(f32) void;
......@@ -77,11 +94,11 @@ extern fn c_f64(f64) void;
7794extern fn c_five_floats(f32, f32, f32, f32, f32) void;
7895
7996export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void {
80 expect(a == 1.0) catch @panic("test failure");
81 expect(b == 2.0) catch @panic("test failure");
82 expect(c == 3.0) catch @panic("test failure");
83 expect(d == 4.0) catch @panic("test failure");
84 expect(e == 5.0) catch @panic("test failure");
97 expect(a == 1.0) catch @panic("test failure: zig_five_floats 1.0");
98 expect(b == 2.0) catch @panic("test failure: zig_five_floats 2.0");
99 expect(c == 3.0) catch @panic("test failure: zig_five_floats 3.0");
100 expect(d == 4.0) catch @panic("test failure: zig_five_floats 4.0");
101 expect(e == 5.0) catch @panic("test failure: zig_five_floats 5.0");
85102}
86103
87104test "C ABI floats" {
......@@ -91,10 +108,10 @@ test "C ABI floats" {
91108}
92109
93110export fn zig_f32(x: f32) void {
94 expect(x == 12.34) catch @panic("test failure");
111 expect(x == 12.34) catch @panic("test failure: zig_f32");
95112}
96113export fn zig_f64(x: f64) void {
97 expect(x == 56.78) catch @panic("test failure");
114 expect(x == 56.78) catch @panic("test failure: zig_f64");
98115}
99116
100117extern fn c_ptr(*anyopaque) void;
......@@ -104,7 +121,7 @@ test "C ABI pointer" {
104121}
105122
106123export fn zig_ptr(x: *anyopaque) void {
107 expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure");
124 expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure: zig_ptr");
108125}
109126
110127extern fn c_bool(bool) void;
......@@ -114,7 +131,7 @@ test "C ABI bool" {
114131}
115132
116133export fn zig_bool(x: bool) void {
117 expect(x) catch @panic("test failure");
134 expect(x) catch @panic("test failure: zig_bool");
118135}
119136
120137const BigStruct = extern struct {
......@@ -138,11 +155,11 @@ test "C ABI big struct" {
138155}
139156
140157export fn zig_big_struct(x: BigStruct) void {
141 expect(x.a == 1) catch @panic("test failure");
142 expect(x.b == 2) catch @panic("test failure");
143 expect(x.c == 3) catch @panic("test failure");
144 expect(x.d == 4) catch @panic("test failure");
145 expect(x.e == 5) catch @panic("test failure");
158 expect(x.a == 1) catch @panic("test failure: zig_big_struct 1");
159 expect(x.b == 2) catch @panic("test failure: zig_big_struct 2");
160 expect(x.c == 3) catch @panic("test failure: zig_big_struct 3");
161 expect(x.d == 4) catch @panic("test failure: zig_big_struct 4");
162 expect(x.e == 5) catch @panic("test failure: zig_big_struct 5");
146163}
147164
148165const BigUnion = extern union {
......@@ -164,11 +181,11 @@ test "C ABI big union" {
164181}
165182
166183export fn zig_big_union(x: BigUnion) void {
167 expect(x.a.a == 1) catch @panic("test failure");
168 expect(x.a.b == 2) catch @panic("test failure");
169 expect(x.a.c == 3) catch @panic("test failure");
170 expect(x.a.d == 4) catch @panic("test failure");
171 expect(x.a.e == 5) catch @panic("test failure");
184 expect(x.a.a == 1) catch @panic("test failure: zig_big_union a");
185 expect(x.a.b == 2) catch @panic("test failure: zig_big_union b");
186 expect(x.a.c == 3) catch @panic("test failure: zig_big_union c");
187 expect(x.a.d == 4) catch @panic("test failure: zig_big_union d");
188 expect(x.a.e == 5) catch @panic("test failure: zig_big_union e");
172189}
173190
174191const MedStructMixed = extern struct {