authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-10 22:45:46+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-10 20:52:36-04:00
log74673b7f69b27dc39a653f92eb58bba71e289f39
treea714fbce1b781835a3d284591f7cb0363660bbda
parent4d7f5a1917f569506682bbb6ee5af672ab1fd8e8

stage2 llvm: implement more C ABI


3 files changed, 119 insertions(+), 10 deletions(-)

src/codegen/llvm.zig+115-9
...@@ -921,6 +921,40 @@ pub const Object = struct {...@@ -921,6 +921,40 @@ pub const Object = struct {
921 };921 };
922 try args.append(loaded);922 try args.append(loaded);
923 },923 },
924 .multiple_llvm_float => {
925 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
926 const param_ty = fn_info.param_types[it.zig_index - 1];
927 const param_llvm_ty = try dg.lowerType(param_ty);
928 const param_alignment = param_ty.abiAlignment(target);
929 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
930 arg_ptr.setAlignment(param_alignment);
931 var field_types_buf: [8]*const llvm.Type = undefined;
932 const field_types = field_types_buf[0..llvm_floats.len];
933 for (llvm_floats) |float_bits, i| {
934 switch (float_bits) {
935 64 => field_types[i] = dg.context.doubleType(),
936 80 => field_types[i] = dg.context.x86FP80Type(),
937 else => {},
938 }
939 }
940 const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
941 const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
942 for (llvm_floats) |_, i_usize| {
943 const i = @intCast(c_uint, i_usize);
944 const param = llvm_func.getParam(i);
945 const field_ptr = builder.buildStructGEP(casted_ptr, i, "");
946 const store_inst = builder.buildStore(param, field_ptr);
947 store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
948 }
949
950 const is_by_ref = isByRef(param_ty);
951 const loaded = if (is_by_ref) arg_ptr else l: {
952 const load_inst = builder.buildLoad(arg_ptr, "");
953 load_inst.setAlignment(param_alignment);
954 break :l load_inst;
955 };
956 try args.append(loaded);
957 },
924 .as_u16 => {958 .as_u16 => {
925 const param = llvm_func.getParam(llvm_arg_i);959 const param = llvm_func.getParam(llvm_arg_i);
926 llvm_arg_i += 1;960 llvm_arg_i += 1;
...@@ -2341,6 +2375,14 @@ pub const DeclGen = struct {...@@ -2341,6 +2375,14 @@ pub const DeclGen = struct {
2341 dg.addFnAttr(llvm_fn, "noreturn");2375 dg.addFnAttr(llvm_fn, "noreturn");
2342 }2376 }
23432377
2378 var llvm_arg_i = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing);
2379 var it = iterateParamTypes(dg, fn_info);
2380 while (it.next()) |_| : (llvm_arg_i += 1) {
2381 if (!it.byval_attr) continue;
2382 const param = llvm_fn.getParam(llvm_arg_i);
2383 llvm_fn.addByValAttr(llvm_arg_i, param.typeOf().getElementType());
2384 }
2385
2344 return llvm_fn;2386 return llvm_fn;
2345 }2387 }
23462388
...@@ -2894,6 +2936,18 @@ pub const DeclGen = struct {...@@ -2894,6 +2936,18 @@ pub const DeclGen = struct {
2894 llvm_params.appendAssumeCapacity(big_int_ty);2936 llvm_params.appendAssumeCapacity(big_int_ty);
2895 }2937 }
2896 },2938 },
2939 .multiple_llvm_float => {
2940 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
2941 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
2942 for (llvm_ints) |float_bits| {
2943 const float_ty = switch (float_bits) {
2944 64 => dg.context.doubleType(),
2945 80 => dg.context.x86FP80Type(),
2946 else => unreachable,
2947 };
2948 llvm_params.appendAssumeCapacity(float_ty);
2949 }
2950 },
2897 .as_u16 => {2951 .as_u16 => {
2898 try llvm_params.append(dg.context.intType(16));2952 try llvm_params.append(dg.context.intType(16));
2899 },2953 },
...@@ -4402,6 +4456,39 @@ pub const FuncGen = struct {...@@ -4402,6 +4456,39 @@ pub const FuncGen = struct {
4402 llvm_args.appendAssumeCapacity(load_inst);4456 llvm_args.appendAssumeCapacity(load_inst);
4403 }4457 }
4404 },4458 },
4459 .multiple_llvm_float => {
4460 const arg = args[it.zig_index - 1];
4461 const param_ty = self.air.typeOf(arg);
4462 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
4463 const llvm_arg = try self.resolveInst(arg);
4464 const is_by_ref = isByRef(param_ty);
4465 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4466 const p = self.buildAlloca(llvm_arg.typeOf());
4467 const store_inst = self.builder.buildStore(llvm_arg, p);
4468 store_inst.setAlignment(param_ty.abiAlignment(target));
4469 break :p p;
4470 };
4471
4472 var field_types_buf: [8]*const llvm.Type = undefined;
4473 const field_types = field_types_buf[0..llvm_floats.len];
4474 for (llvm_floats) |float_bits, i| {
4475 switch (float_bits) {
4476 64 => field_types[i] = self.dg.context.doubleType(),
4477 80 => field_types[i] = self.dg.context.x86FP80Type(),
4478 else => {},
4479 }
4480 }
4481 const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
4482 const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
4483 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
4484 for (llvm_floats) |_, i_usize| {
4485 const i = @intCast(c_uint, i_usize);
4486 const field_ptr = self.builder.buildStructGEP(casted_ptr, i, "");
4487 const load_inst = self.builder.buildLoad(field_ptr, "");
4488 load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
4489 llvm_args.appendAssumeCapacity(load_inst);
4490 }
4491 },
4405 .as_u16 => {4492 .as_u16 => {
4406 const arg = args[it.zig_index - 1];4493 const arg = args[it.zig_index - 1];
4407 const llvm_arg = try self.resolveInst(arg);4494 const llvm_arg = try self.resolveInst(arg);
...@@ -9367,16 +9454,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -9367,16 +9454,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
9367 llvm_types_index += 1;9454 llvm_types_index += 1;
9368 },9455 },
9369 .sse => {9456 .sse => {
9370 @panic("TODO");9457 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9458 llvm_types_index += 1;
9371 },9459 },
9372 .sseup => {9460 .sseup => {
9373 @panic("TODO");9461 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9462 llvm_types_index += 1;
9374 },9463 },
9375 .x87 => {9464 .x87 => {
9376 @panic("TODO");9465 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9466 llvm_types_index += 1;
9377 },9467 },
9378 .x87up => {9468 .x87up => {
9379 @panic("TODO");9469 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9470 llvm_types_index += 1;
9380 },9471 },
9381 .complex_x87 => {9472 .complex_x87 => {
9382 @panic("TODO");9473 @panic("TODO");
...@@ -9422,6 +9513,7 @@ const ParamTypeIterator = struct {...@@ -9422,6 +9513,7 @@ const ParamTypeIterator = struct {
9422 target: std.Target,9513 target: std.Target,
9423 llvm_types_len: u32,9514 llvm_types_len: u32,
9424 llvm_types_buffer: [8]u16,9515 llvm_types_buffer: [8]u16,
9516 byval_attr: bool,
94259517
9426 const Lowering = enum {9518 const Lowering = enum {
9427 no_bits,9519 no_bits,
...@@ -9429,6 +9521,7 @@ const ParamTypeIterator = struct {...@@ -9429,6 +9521,7 @@ const ParamTypeIterator = struct {
9429 byref,9521 byref,
9430 abi_sized_int,9522 abi_sized_int,
9431 multiple_llvm_ints,9523 multiple_llvm_ints,
9524 multiple_llvm_float,
9432 slice,9525 slice,
9433 as_u16,9526 as_u16,
9434 };9527 };
...@@ -9436,6 +9529,7 @@ const ParamTypeIterator = struct {...@@ -9436,6 +9529,7 @@ const ParamTypeIterator = struct {
9436 pub fn next(it: *ParamTypeIterator) ?Lowering {9529 pub fn next(it: *ParamTypeIterator) ?Lowering {
9437 if (it.zig_index >= it.fn_info.param_types.len) return null;9530 if (it.zig_index >= it.fn_info.param_types.len) return null;
9438 const ty = it.fn_info.param_types[it.zig_index];9531 const ty = it.fn_info.param_types[it.zig_index];
9532 it.byval_attr = false;
9439 return nextInner(it, ty);9533 return nextInner(it, ty);
9440 }9534 }
94419535
...@@ -9521,6 +9615,7 @@ const ParamTypeIterator = struct {...@@ -9521,6 +9615,7 @@ const ParamTypeIterator = struct {
9521 .memory => {9615 .memory => {
9522 it.zig_index += 1;9616 it.zig_index += 1;
9523 it.llvm_index += 1;9617 it.llvm_index += 1;
9618 it.byval_attr = true;
9524 return .byref;9619 return .byref;
9525 },9620 },
9526 .sse => {9621 .sse => {
...@@ -9540,6 +9635,7 @@ const ParamTypeIterator = struct {...@@ -9540,6 +9635,7 @@ const ParamTypeIterator = struct {
9540 if (classes[0] == .memory) {9635 if (classes[0] == .memory) {
9541 it.zig_index += 1;9636 it.zig_index += 1;
9542 it.llvm_index += 1;9637 it.llvm_index += 1;
9638 it.byval_attr = true;
9543 return .byref;9639 return .byref;
9544 }9640 }
9545 var llvm_types_buffer: [8]u16 = undefined;9641 var llvm_types_buffer: [8]u16 = undefined;
...@@ -9551,16 +9647,20 @@ const ParamTypeIterator = struct {...@@ -9551,16 +9647,20 @@ const ParamTypeIterator = struct {
9551 llvm_types_index += 1;9647 llvm_types_index += 1;
9552 },9648 },
9553 .sse => {9649 .sse => {
9554 @panic("TODO");9650 llvm_types_buffer[llvm_types_index] = 64;
9651 llvm_types_index += 1;
9555 },9652 },
9556 .sseup => {9653 .sseup => {
9557 @panic("TODO");9654 llvm_types_buffer[llvm_types_index] = 64;
9655 llvm_types_index += 1;
9558 },9656 },
9559 .x87 => {9657 .x87 => {
9560 @panic("TODO");9658 llvm_types_buffer[llvm_types_index] = 80;
9659 llvm_types_index += 1;
9561 },9660 },
9562 .x87up => {9661 .x87up => {
9563 @panic("TODO");9662 llvm_types_buffer[llvm_types_index] = 80;
9663 llvm_types_index += 1;
9564 },9664 },
9565 .complex_x87 => {9665 .complex_x87 => {
9566 @panic("TODO");9666 @panic("TODO");
...@@ -9574,11 +9674,16 @@ const ParamTypeIterator = struct {...@@ -9574,11 +9674,16 @@ const ParamTypeIterator = struct {
9574 it.llvm_index += 1;9674 it.llvm_index += 1;
9575 return .abi_sized_int;9675 return .abi_sized_int;
9576 }9676 }
9677 if (classes[0] == .sse and classes[1] == .none) {
9678 it.zig_index += 1;
9679 it.llvm_index += 1;
9680 return .byval;
9681 }
9577 it.llvm_types_buffer = llvm_types_buffer;9682 it.llvm_types_buffer = llvm_types_buffer;
9578 it.llvm_types_len = llvm_types_index;9683 it.llvm_types_len = llvm_types_index;
9579 it.llvm_index += llvm_types_index;9684 it.llvm_index += llvm_types_index;
9580 it.zig_index += 1;9685 it.zig_index += 1;
9581 return .multiple_llvm_ints;9686 return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
9582 },9687 },
9583 },9688 },
9584 .wasm32 => {9689 .wasm32 => {
...@@ -9619,6 +9724,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp...@@ -9619,6 +9724,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
9619 .target = dg.module.getTarget(),9724 .target = dg.module.getTarget(),
9620 .llvm_types_buffer = undefined,9725 .llvm_types_buffer = undefined,
9621 .llvm_types_len = 0,9726 .llvm_types_len = 0,
9727 .byval_attr = false,
9622 };9728 };
9623}9729}
96249730
src/codegen/llvm/bindings.zig+3
...@@ -248,6 +248,9 @@ pub const Value = opaque {...@@ -248,6 +248,9 @@ pub const Value = opaque {
248248
249 pub const addFunctionAttr = ZigLLVMAddFunctionAttr;249 pub const addFunctionAttr = ZigLLVMAddFunctionAttr;
250 extern fn ZigLLVMAddFunctionAttr(Fn: *const Value, attr_name: [*:0]const u8, attr_value: [*:0]const u8) void;250 extern fn ZigLLVMAddFunctionAttr(Fn: *const Value, attr_name: [*:0]const u8, attr_value: [*:0]const u8) void;
251
252 pub const addByValAttr = ZigLLVMAddByValAttr;
253 extern fn ZigLLVMAddByValAttr(Fn: *const Value, ArgNo: c_uint, type: *const Type) void;
251};254};
252255
253pub const Type = opaque {256pub const Type = opaque {
test/standalone.zig+1-1
...@@ -40,7 +40,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -40,7 +40,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
40 }40 }
41 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/148141 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
42 if (builtin.cpu.arch == .x86_64) {42 if (builtin.cpu.arch == .x86_64) {
43 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/1222243 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/12222
44 cases.addBuildFile("test/c_abi/build.zig", .{});44 cases.addBuildFile("test/c_abi/build.zig", .{});
45 }45 }
46 }46 }