| author | |
| committer | |
| log | 28ae5d4158b084d17e55e73aec4c37e22885bd78 |
| tree | ac2e5760c328e300f471d1faa919fa403718db55 |
| parent | 4059242f44e28dc2c8f9837c2033060974fd253f |
Closes #316363 files changed, 43 insertions(+), 8 deletions(-)
src/codegen/llvm.zig+5-6| ... | @@ -1259,11 +1259,6 @@ pub const Object = struct { | ... | @@ -1259,11 +1259,6 @@ pub const Object = struct { |
| 1259 | defer if (deinit_wip) wip.deinit(); | 1259 | defer if (deinit_wip) wip.deinit(); |
| 1260 | wip.cursor = .{ .block = try wip.block(0, "Entry") }; | 1260 | wip.cursor = .{ .block = try wip.block(0, "Entry") }; |
| 1261 | 1261 | ||
| 1262 | if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { | ||
| 1263 | .signed => try attributes.addRetAttr(.signext, &o.builder), | ||
| 1264 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), | ||
| 1265 | }; | ||
| 1266 | |||
| 1267 | // This is the list of args we will use that correspond directly to the AIR arg | 1262 | // This is the list of args we will use that correspond directly to the AIR arg |
| 1268 | // instructions. Depending on the calling convention, this list is not necessarily | 1263 | // instructions. Depending on the calling convention, this list is not necessarily |
| 1269 | // a bijection with the actual LLVM parameters of the function. | 1264 | // a bijection with the actual LLVM parameters of the function. |
| ... | @@ -2812,7 +2807,11 @@ pub const Object = struct { | ... | @@ -2812,7 +2807,11 @@ pub const Object = struct { |
| 2812 | const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type)); | 2807 | const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type)); |
| 2813 | try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder); | 2808 | try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder); |
| 2814 | it.llvm_index += 1; | 2809 | it.llvm_index += 1; |
| 2815 | } | 2810 | } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { |
| 2811 | .signed => try attributes.addRetAttr(.signext, &o.builder), | ||
| 2812 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), | ||
| 2813 | }; | ||
| 2814 | |||
| 2816 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; | 2815 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; |
| 2817 | if (err_return_tracing) { | 2816 | if (err_return_tracing) { |
| 2818 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); | 2817 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); |
src/codegen/llvm/FuncGen.zig+8-2| ... | @@ -611,14 +611,20 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif | ... | @@ -611,14 +611,20 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 611 | .no_suspend, .always_inline, .compile_time => unreachable, | 611 | .no_suspend, .always_inline, .compile_time => unreachable, |
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | const ret_ptr = if (!sret) null else blk: { | 614 | const ret_ptr = if (sret) ret_ptr: { |
| 615 | const llvm_ret_ty = try o.lowerType(return_type); | 615 | const llvm_ret_ty = try o.lowerType(return_type); |
| 616 | try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder); | 616 | try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder); |
| 617 | 617 | ||
| 618 | const alignment = return_type.abiAlignment(zcu).toLlvm(); | 618 | const alignment = return_type.abiAlignment(zcu).toLlvm(); |
| 619 | const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); | 619 | const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); |
| 620 | try llvm_args.append(ret_ptr); | 620 | try llvm_args.append(ret_ptr); |
| 621 | break :blk ret_ptr; | 621 | break :ret_ptr ret_ptr; |
| 622 | } else ret_ptr: { | ||
| 623 | if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { | ||
| 624 | .signed => try attributes.addRetAttr(.signext, &o.builder), | ||
| 625 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), | ||
| 626 | }; | ||
| 627 | break :ret_ptr null; | ||
| 622 | }; | 628 | }; |
| 623 | 629 | ||
| 624 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; | 630 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; |
test/behavior/call.zig+30| ... | @@ -731,3 +731,33 @@ test "tail call function pointer" { | ... | @@ -731,3 +731,33 @@ test "tail call function pointer" { |
| 731 | 731 | ||
| 732 | S.foo(100); | 732 | S.foo(100); |
| 733 | } | 733 | } |
| 734 | |||
| 735 | test "tail call with potentially extended types" { | ||
| 736 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 737 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 738 | |||
| 739 | if (builtin.zig_backend == .stage2_llvm) { | ||
| 740 | if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) { | ||
| 741 | return error.SkipZigTest; | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls | ||
| 746 | |||
| 747 | const S = struct { | ||
| 748 | fn Test(comptime Return: type) type { | ||
| 749 | return struct { | ||
| 750 | fn callee(@"u8": u8, @"i8": i8, @"u16": u16, @"i16": i16) callconv(.c) Return { | ||
| 751 | return @intCast(@as(i32, @"u8") + @as(i32, @"i8") + @as(i32, @"u16") + @as(i32, @"i16")); | ||
| 752 | } | ||
| 753 | fn caller(@"u8": u8, @"i8": i8, @"u16": u16, @"i16": i16) callconv(.c) Return { | ||
| 754 | return @call(.always_tail, callee, .{ @"u8", @"i8", @"u16", @"i16" }); | ||
| 755 | } | ||
| 756 | }; | ||
| 757 | } | ||
| 758 | }; | ||
| 759 | try std.testing.expect(S.Test(u8).caller(1, -2, 3, 4) == 6); | ||
| 760 | try std.testing.expect(S.Test(i8).caller(5, -6, 7, -8) == -2); | ||
| 761 | try std.testing.expect(S.Test(u16).caller(9, 10, 11, 12) == 42); | ||
| 762 | try std.testing.expect(S.Test(i16).caller(13, 14, 15, -16) == 26); | ||
| 763 | } |