From 65bea9ac079e8d580f710b62f3c8cfcb3821d2cb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 26 Apr 2024 13:40:42 -0700 Subject: [PATCH] LLVM 18 update: avoid passing vectors sometimes LLVM now refuses to lower arguments and return values on x86 targets when the total vector bit size is >= 512. This code detects such a situation and uses byref instead of byval. --- src/codegen/llvm.zig | 27 +++++++++++++++++++++++++-- src/type.zig | 7 +++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4142ad0a19..458c187fec 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10990,12 +10990,27 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ }; } +fn returnTypeByRef(zcu: *Zcu, target: std.Target, ty: Type) bool { + if (isByRef(ty, zcu)) { + return true; + } else if (target.cpu.arch.isX86() and + !std.Target.x86.featureSetHas(target.cpu.features, .evex512) and + ty.totalVectorBits(zcu) >= 512) + { + // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns + // "512-bit vector arguments require 'evex512' for AVX512" + return true; + } else { + return false; + } +} + fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Target) bool { const return_type = Type.fromInterned(fn_info.return_type); if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false; return switch (fn_info.cc) { - .Unspecified, .Inline => isByRef(return_type, zcu), + .Unspecified, .Inline => returnTypeByRef(zcu, target, return_type), .C => switch (target.cpu.arch) { .mips, .mipsel => false, .x86 => isByRef(return_type, zcu), @@ -11043,7 +11058,8 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu switch (fn_info.cc) { .Unspecified, .Inline, - => return if (isByRef(return_type, mod)) .void else o.lowerType(return_type), + => return if (returnTypeByRef(mod, target, return_type)) .void else o.lowerType(return_type), + .C => { switch (target.cpu.arch) { .mips, .mipsel => return o.lowerType(return_type), @@ -11266,6 +11282,13 @@ const ParamTypeIterator = struct { return .slice; } else if (isByRef(ty, zcu)) { return .byref; + } else if (target.cpu.arch.isX86() and + !std.Target.x86.featureSetHas(target.cpu.features, .evex512) and + ty.totalVectorBits(zcu) >= 512) + { + // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns + // "512-bit vector arguments require 'evex512' for AVX512" + return .byref; } else { return .byval; } diff --git a/src/type.zig b/src/type.zig index fcacfaf9e6..5fc6e962c4 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2804,6 +2804,13 @@ pub const Type = struct { return ty.zigTypeTag(mod) == .Vector; } + /// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len. + pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 { + if (!ty.isVector(zcu)) return 0; + const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type; + return v.len * Type.fromInterned(v.child).bitSize(zcu); + } + pub fn isArrayOrVector(ty: Type, mod: *const Module) bool { return switch (ty.zigTypeTag(mod)) { .Array, .Vector => true,