| ... | @@ -774,7 +774,7 @@ pub fn generate( | ... | @@ -774,7 +774,7 @@ pub fn generate( |
| 774 | ); | 774 | ); |
| 775 | | 775 | |
| 776 | const fn_info = zcu.typeToFunc(fn_type).?; | 776 | const fn_info = zcu.typeToFunc(fn_type).?; |
| 777 | var call_info = function.resolveCallingConventionValues(fn_info) catch |err| switch (err) { | 777 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}) catch |err| switch (err) { |
| 778 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, | 778 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 779 | error.OutOfRegisters => return Result{ | 779 | error.OutOfRegisters => return Result{ |
| 780 | .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), | 780 | .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), |
| ... | @@ -3552,7 +3552,14 @@ fn genCall( | ... | @@ -3552,7 +3552,14 @@ fn genCall( |
| 3552 | }; | 3552 | }; |
| 3553 | | 3553 | |
| 3554 | const fn_info = zcu.typeToFunc(fn_ty).?; | 3554 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 3555 | var call_info = try self.resolveCallingConventionValues(fn_info); | 3555 | |
| | 3556 | const allocator = self.gpa; |
| | 3557 | |
| | 3558 | const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len); |
| | 3559 | defer allocator.free(var_args); |
| | 3560 | for (var_args, arg_tys[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; |
| | 3561 | |
| | 3562 | var call_info = try self.resolveCallingConventionValues(fn_info, var_args); |
| 3556 | defer call_info.deinit(self); | 3563 | defer call_info.deinit(self); |
| 3557 | | 3564 | |
| 3558 | // We need a properly aligned and sized call frame to be able to call this function. | 3565 | // We need a properly aligned and sized call frame to be able to call this function. |
| ... | @@ -5318,16 +5325,19 @@ const CallMCValues = struct { | ... | @@ -5318,16 +5325,19 @@ const CallMCValues = struct { |
| 5318 | fn resolveCallingConventionValues( | 5325 | fn resolveCallingConventionValues( |
| 5319 | self: *Self, | 5326 | self: *Self, |
| 5320 | fn_info: InternPool.Key.FuncType, | 5327 | fn_info: InternPool.Key.FuncType, |
| | 5328 | var_args: []const Type, |
| 5321 | ) !CallMCValues { | 5329 | ) !CallMCValues { |
| 5322 | const zcu = self.bin_file.comp.module.?; | 5330 | const zcu = self.bin_file.comp.module.?; |
| 5323 | const ip = &zcu.intern_pool; | 5331 | const ip = &zcu.intern_pool; |
| 5324 | | 5332 | |
| 5325 | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len); | 5333 | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); |
| 5326 | defer self.gpa.free(param_types); | 5334 | defer self.gpa.free(param_types); |
| 5327 | | 5335 | |
| 5328 | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { | 5336 | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { |
| 5329 | dest.* = Type.fromInterned(src); | 5337 | dest.* = Type.fromInterned(src); |
| 5330 | } | 5338 | } |
| | 5339 | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| |
| | 5340 | param_ty.* = self.promoteVarArg(arg_ty); |
| 5331 | | 5341 | |
| 5332 | const cc = fn_info.cc; | 5342 | const cc = fn_info.cc; |
| 5333 | var result: CallMCValues = .{ | 5343 | var result: CallMCValues = .{ |
| ... | @@ -5514,3 +5524,33 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Module) u64 { | ... | @@ -5514,3 +5524,33 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Module) u64 { |
| 5514 | return 0; | 5524 | return 0; |
| 5515 | } | 5525 | } |
| 5516 | } | 5526 | } |
| | 5527 | |
| | 5528 | fn promoteInt(self: *Self, ty: Type) Type { |
| | 5529 | const mod = self.bin_file.comp.module.?; |
| | 5530 | const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { |
| | 5531 | .bool_type => .{ .signedness = .unsigned, .bits = 1 }, |
| | 5532 | else => if (ty.isAbiInt(mod)) ty.intInfo(mod) else return ty, |
| | 5533 | }; |
| | 5534 | for ([_]Type{ |
| | 5535 | Type.c_int, Type.c_uint, |
| | 5536 | Type.c_long, Type.c_ulong, |
| | 5537 | Type.c_longlong, Type.c_ulonglong, |
| | 5538 | }) |promote_ty| { |
| | 5539 | const promote_info = promote_ty.intInfo(mod); |
| | 5540 | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| | 5541 | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| | 5542 | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| | 5543 | } |
| | 5544 | return ty; |
| | 5545 | } |
| | 5546 | |
| | 5547 | fn promoteVarArg(self: *Self, ty: Type) Type { |
| | 5548 | if (!ty.isRuntimeFloat()) return self.promoteInt(ty); |
| | 5549 | switch (ty.floatBits(self.target.*)) { |
| | 5550 | 32, 64 => return Type.f64, |
| | 5551 | else => |float_bits| { |
| | 5552 | assert(float_bits == self.target.c_type_bit_size(.longdouble)); |
| | 5553 | return Type.c_longdouble; |
| | 5554 | }, |
| | 5555 | } |
| | 5556 | } |