From 65d37239682b6418b6dd25f07187ae99088e67f0 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 30 Aug 2022 17:13:35 +0300 Subject: [PATCH] Sema: check that target supports tail calls --- lib/std/target.zig | 10 ++++++++++ src/Sema.zig | 4 ++++ test/behavior/call.zig | 4 ++++ test/cases/taill_call_noreturn.zig | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index 64f9f97809..7b4a468a61 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1440,6 +1440,16 @@ pub const Target = struct { return !self.cpu.arch.isWasm(); } + pub fn supportsTailCall(self: Target) bool { + switch (self.cpu.arch) { + .wasm32, .wasm64 => return wasm.featureSetHas(self.cpu.features, .tail_call), + // TODO these might not be true but LLVM doesn't seem to be able to handle them + .mips, .mipsel, .mips64, .mips64el => return false, + .powerpc, .powerpcle, .powerpc64, .powerpc64le => return false, + else => return true, + } + } + pub const FloatAbi = enum { hard, soft, diff --git a/src/Sema.zig b/src/Sema.zig index 74f19e5b93..8cde9d7e12 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6160,6 +6160,10 @@ fn analyzeCall( } fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { + const target = sema.mod.getTarget(); + if (!target.supportsTailCall()) { + return sema.fail(block, call_src, "unable to perform tail call: target does not support tail calls", .{}); + } const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); if (!func_ty.eql(func_decl.ty, sema.mod)) { return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 4c697ed542..4a4ff4fb78 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -270,6 +270,8 @@ test "forced tail call" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (comptime !builtin.target.supportsTailCall()) return error.SkipZigTest; + const S = struct { fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 { if (n == 0) return a; @@ -296,6 +298,8 @@ test "inline call preserves tail call" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (comptime !builtin.target.supportsTailCall()) return error.SkipZigTest; + const max = std.math.maxInt(u16); const S = struct { var a: u16 = 0; diff --git a/test/cases/taill_call_noreturn.zig b/test/cases/taill_call_noreturn.zig index 0c2497d6ce..fabb9e729b 100644 --- a/test/cases/taill_call_noreturn.zig +++ b/test/cases/taill_call_noreturn.zig @@ -15,4 +15,4 @@ pub fn main() void { // run // backend=llvm -// target=native +// target=x86_64-linux,x86_64-macos,aarch64-linux,aarch64-macos