llvm: fix missing return attributes

Closes #31636
This commit is contained in:
Jacob Young
2026-04-02 03:13:07 -04:00
committed by Andrew Kelley
parent 4059242f44
commit 28ae5d4158
3 changed files with 43 additions and 8 deletions
+5 -6
View File
@@ -1259,11 +1259,6 @@ pub const Object = struct {
defer if (deinit_wip) wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
.signed => try attributes.addRetAttr(.signext, &o.builder),
.unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
};
// This is the list of args we will use that correspond directly to the AIR arg
// instructions. Depending on the calling convention, this list is not necessarily
// a bijection with the actual LLVM parameters of the function.
@@ -2812,7 +2807,11 @@ pub const Object = struct {
const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type));
try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder);
it.llvm_index += 1;
}
} else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
.signed => try attributes.addRetAttr(.signext, &o.builder),
.unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
};
const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
if (err_return_tracing) {
try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder);
+8 -2
View File
@@ -611,14 +611,20 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
.no_suspend, .always_inline, .compile_time => unreachable,
}
const ret_ptr = if (!sret) null else blk: {
const ret_ptr = if (sret) ret_ptr: {
const llvm_ret_ty = try o.lowerType(return_type);
try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
const alignment = return_type.abiAlignment(zcu).toLlvm();
const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
try llvm_args.append(ret_ptr);
break :blk ret_ptr;
break :ret_ptr ret_ptr;
} else ret_ptr: {
if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
.signed => try attributes.addRetAttr(.signext, &o.builder),
.unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
};
break :ret_ptr null;
};
const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
+30
View File
@@ -731,3 +731,33 @@ test "tail call function pointer" {
S.foo(100);
}
test "tail call with potentially extended types" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) {
if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) {
return error.SkipZigTest;
}
}
if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
const S = struct {
fn Test(comptime Return: type) type {
return struct {
fn callee(@"u8": u8, @"i8": i8, @"u16": u16, @"i16": i16) callconv(.c) Return {
return @intCast(@as(i32, @"u8") + @as(i32, @"i8") + @as(i32, @"u16") + @as(i32, @"i16"));
}
fn caller(@"u8": u8, @"i8": i8, @"u16": u16, @"i16": i16) callconv(.c) Return {
return @call(.always_tail, callee, .{ @"u8", @"i8", @"u16", @"i16" });
}
};
}
};
try std.testing.expect(S.Test(u8).caller(1, -2, 3, 4) == 6);
try std.testing.expect(S.Test(i8).caller(5, -6, 7, -8) == -2);
try std.testing.expect(S.Test(u16).caller(9, 10, 11, 12) == 42);
try std.testing.expect(S.Test(i16).caller(13, 14, 15, -16) == 26);
}