authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-26 13:40:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-08 19:37:28-07:00
log65bea9ac079e8d580f710b62f3c8cfcb3821d2cb
treec0dc0933f6a0ca691f4a1e7055cb04fdae1b02b1
parent21f1e76efeb2a1c1c9df32628b81713f9876d5ab

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.

2 files changed, 32 insertions(+), 2 deletions(-)

src/codegen/llvm.zig+25-2
...@@ -10990,12 +10990,27 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ...@@ -10990,12 +10990,27 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ
10990 };10990 };
10991}10991}
1099210992
10993fn returnTypeByRef(zcu: *Zcu, target: std.Target, ty: Type) bool {
10994 if (isByRef(ty, zcu)) {
10995 return true;
10996 } else if (target.cpu.arch.isX86() and
10997 !std.Target.x86.featureSetHas(target.cpu.features, .evex512) and
10998 ty.totalVectorBits(zcu) >= 512)
10999 {
11000 // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns
11001 // "512-bit vector arguments require 'evex512' for AVX512"
11002 return true;
11003 } else {
11004 return false;
11005 }
11006}
11007
10993fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Target) bool {11008fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: std.Target) bool {
10994 const return_type = Type.fromInterned(fn_info.return_type);11009 const return_type = Type.fromInterned(fn_info.return_type);
10995 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;11010 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
1099611011
10997 return switch (fn_info.cc) {11012 return switch (fn_info.cc) {
10998 .Unspecified, .Inline => isByRef(return_type, zcu),11013 .Unspecified, .Inline => returnTypeByRef(zcu, target, return_type),
10999 .C => switch (target.cpu.arch) {11014 .C => switch (target.cpu.arch) {
11000 .mips, .mipsel => false,11015 .mips, .mipsel => false,
11001 .x86 => isByRef(return_type, zcu),11016 .x86 => isByRef(return_type, zcu),
...@@ -11043,7 +11058,8 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu...@@ -11043,7 +11058,8 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
11043 switch (fn_info.cc) {11058 switch (fn_info.cc) {
11044 .Unspecified,11059 .Unspecified,
11045 .Inline,11060 .Inline,
11046 => return if (isByRef(return_type, mod)) .void else o.lowerType(return_type),11061 => return if (returnTypeByRef(mod, target, return_type)) .void else o.lowerType(return_type),
11062
11047 .C => {11063 .C => {
11048 switch (target.cpu.arch) {11064 switch (target.cpu.arch) {
11049 .mips, .mipsel => return o.lowerType(return_type),11065 .mips, .mipsel => return o.lowerType(return_type),
...@@ -11266,6 +11282,13 @@ const ParamTypeIterator = struct {...@@ -11266,6 +11282,13 @@ const ParamTypeIterator = struct {
11266 return .slice;11282 return .slice;
11267 } else if (isByRef(ty, zcu)) {11283 } else if (isByRef(ty, zcu)) {
11268 return .byref;11284 return .byref;
11285 } else if (target.cpu.arch.isX86() and
11286 !std.Target.x86.featureSetHas(target.cpu.features, .evex512) and
11287 ty.totalVectorBits(zcu) >= 512)
11288 {
11289 // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns
11290 // "512-bit vector arguments require 'evex512' for AVX512"
11291 return .byref;
11269 } else {11292 } else {
11270 return .byval;11293 return .byval;
11271 }11294 }
src/type.zig+7
...@@ -2804,6 +2804,13 @@ pub const Type = struct {...@@ -2804,6 +2804,13 @@ pub const Type = struct {
2804 return ty.zigTypeTag(mod) == .Vector;2804 return ty.zigTypeTag(mod) == .Vector;
2805 }2805 }
28062806
2807 /// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len.
2808 pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 {
2809 if (!ty.isVector(zcu)) return 0;
2810 const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type;
2811 return v.len * Type.fromInterned(v.child).bitSize(zcu);
2812 }
2813
2807 pub fn isArrayOrVector(ty: Type, mod: *const Module) bool {2814 pub fn isArrayOrVector(ty: Type, mod: *const Module) bool {
2808 return switch (ty.zigTypeTag(mod)) {2815 return switch (ty.zigTypeTag(mod)) {
2809 .Array, .Vector => true,2816 .Array, .Vector => true,