Skip to content

Commit 2347ae9

Browse files
committed
[X86] Return illegal vectors in memory
When vector size doesn't fit in native machine vector size, we should return vector via a hidden reference.
1 parent 3cac26f commit 2347ae9

File tree

4 files changed

+79
-21
lines changed

4 files changed

+79
-21
lines changed

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ class LangOptionsBase {
245245
/// construction vtable because it hasn't added 'type' as a substitution.
246246
/// - Skip mangling enclosing class templates of member-like friend
247247
/// function templates.
248+
/// - Incorrectly return illegal vectors (size greater than native
249+
/// vector size) to be returned in illegal registers on x86_64.
248250
Ver19,
249251

250252
/// Conform to the underlying platform's C and C++ ABIs as closely

clang/lib/CodeGen/Targets/X86.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,8 +1298,12 @@ class X86_64ABIInfo : public ABIInfo {
12981298
unsigned &NeededSSE,
12991299
unsigned &MaxVectorWidth) const;
13001300

1301+
// Checks whether vector types for function arguments are illegal
13011302
bool IsIllegalVectorType(QualType Ty) const;
13021303

1304+
// Checks whether vector types for returns are illegal
1305+
bool IsIllegalReturnVectorType(QualType Ty) const;
1306+
13031307
/// The 0.98 ABI revision clarified a lot of ambiguities,
13041308
/// unfortunately in ways that were not always consistent with
13051309
/// certain previous compilers. In particular, platforms which
@@ -1334,6 +1338,16 @@ class X86_64ABIInfo : public ABIInfo {
13341338
return T.isOSLinux() || T.isOSNetBSD();
13351339
}
13361340

1341+
bool returnIllegalVectorsInMem() const {
1342+
// Clang <= 19.0 did not do this.
1343+
if (getContext().getLangOpts().getClangABICompat() <=
1344+
LangOptions::ClangABI::Ver19)
1345+
return false;
1346+
1347+
const llvm::Triple &T = getTarget().getTriple();
1348+
return T.isOSLinux() || T.isOSNetBSD();
1349+
}
1350+
13371351
X86AVXABILevel AVXLevel;
13381352
// Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
13391353
// 64-bit hardware.
@@ -2156,9 +2170,12 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
21562170
}
21572171

21582172
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
2173+
const bool returnIllegalVectorsIndirectly =
2174+
(returnIllegalVectorsInMem() && IsIllegalReturnVectorType(Ty));
2175+
21592176
// If this is a scalar LLVM value then assume LLVM will pass it in the right
21602177
// place naturally.
2161-
if (!isAggregateTypeForABI(Ty)) {
2178+
if (!isAggregateTypeForABI(Ty) && !returnIllegalVectorsIndirectly) {
21622179
// Treat an enum type as its underlying type.
21632180
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
21642181
Ty = EnumTy->getDecl()->getIntegerType();
@@ -2173,12 +2190,23 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
21732190
return getNaturalAlignIndirect(Ty);
21742191
}
21752192

2176-
bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
2193+
static bool IsIllegalVector(QualType Ty, uint64_t Size,
2194+
X86AVXABILevel AVXLevel) {
21772195
if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
2178-
uint64_t Size = getContext().getTypeSize(VecTy);
21792196
unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel);
21802197
if (Size <= 64 || Size > LargestVector)
21812198
return true;
2199+
}
2200+
2201+
return false;
2202+
}
2203+
2204+
bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
2205+
if (IsIllegalVector(Ty, getContext().getTypeSize(Ty), AVXLevel))
2206+
return true;
2207+
2208+
// Maintain backward compatibility
2209+
if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
21822210
QualType EltTy = VecTy->getElementType();
21832211
if (passInt128VectorsInMem() &&
21842212
(EltTy->isSpecificBuiltinType(BuiltinType::Int128) ||
@@ -2189,6 +2217,10 @@ bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
21892217
return false;
21902218
}
21912219

2220+
bool X86_64ABIInfo::IsIllegalReturnVectorType(QualType Ty) const {
2221+
return IsIllegalVector(Ty, getContext().getTypeSize(Ty), AVXLevel);
2222+
}
2223+
21922224
ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
21932225
unsigned freeIntRegs) const {
21942226
// If this is a scalar LLVM value then assume LLVM will pass it in the right
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=REGRET128,MEMRET256,MEMRET512
2+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - -fclang-abi-compat=19 | FileCheck %s --check-prefixes=REGRET128,REGRET256,REGRET512
3+
4+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=REGRET128,REGRET256,MEMRET512
5+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - -fclang-abi-compat=19 | FileCheck %s --check-prefixes=REGRET128,REGRET256,REGRET512
6+
7+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx512f -emit-llvm -o - | FileCheck %s --check-prefixes=REGRET128,REGRET256,REGRET512
8+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx512f -emit-llvm -o - -fclang-abi-compat=19 | FileCheck %s --check-prefixes=REGRET128,REGRET256,REGRET512
9+
10+
#define __MM_MALLOC_H
11+
#include <x86intrin.h>
12+
13+
// REGRET128: define{{.*}} <4 x float> @get2()
14+
__m128 get2() { __m128 r = (__m128){5,6}; return r; }
15+
16+
// MEMRET256: define{{.*}} void @get4(ptr{{.*}} sret(<8 x float>) align 32 %{{.*}})
17+
// REGRET256: define{{.*}} <8 x float> @get4()
18+
__m256 get4() { __m256 r = (__m256){7,8,9,10}; return r; }
19+
20+
// MEMRET512: define{{.*}} void @get8(ptr{{.*}} sret(<16 x float>) align 64 %{{.*}})
21+
// REGRET512: define{{.*}} <16 x float> @get8()
22+
__m512 get8() { __m512 r = (__m512){7,8,9,10,1,2,3,4}; return r; }

clang/test/CodeGen/X86/x86-vec-i128.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,MEM256ALIGN32,MEM512ALIGN64
2-
// RUN: %clang_cc1 -triple x86_64-netbsd %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,MEM256ALIGN32,MEM512ALIGN64
3-
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEM256ALIGN16,MEM512ALIGN16
4-
// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEM256ALIGN32,MEM512ALIGN64
5-
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEM256ALIGN32,MEM512ALIGN64
6-
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - -fclang-abi-compat=9 | FileCheck %s --check-prefixes=CLANG9ABI128,MEM256ALIGN32,MEM512ALIGN64
7-
8-
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,MEM512ALIGN64
9-
// RUN: %clang_cc1 -triple x86_64-netbsd %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,MEM512ALIGN64
10-
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEM512ALIGN32
11-
// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEM512ALIGN64
12-
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEM512ALIGN64
13-
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - -fclang-abi-compat=9 | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEM512ALIGN64
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,MEMRETMEMARG256ALIGN32,MEMRETMEMARG512ALIGN64
2+
// RUN: %clang_cc1 -triple x86_64-netbsd %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,MEMRETMEMARG256ALIGN32,MEMRETMEMARG512ALIGN64
3+
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEMARG256ALIGN16,MEMARG512ALIGN16
4+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEMARG256ALIGN32,MEMARG512ALIGN64
5+
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 %s -target-feature +sse2 -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,MEMARG256ALIGN32,MEMARG512ALIGN64
6+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +sse2 -emit-llvm -o - -fclang-abi-compat=9 | FileCheck %s --check-prefixes=CLANG9ABI128,MEMARG256ALIGN32,MEMARG512ALIGN64
7+
8+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,MEMRETMEMARG512ALIGN64
9+
// RUN: %clang_cc1 -triple x86_64-netbsd %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,MEMRETMEMARG512ALIGN64
10+
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEMARG512ALIGN32
11+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEMARG512ALIGN64
12+
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 %s -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEMARG512ALIGN64
13+
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx -emit-llvm -o - -fclang-abi-compat=9 | FileCheck %s --check-prefixes=CLANG9ABI128,CLANG9ABI256,MEMARG512ALIGN64
1414

1515
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -target-feature +avx512f -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,CLANG10ABI512
1616
// RUN: %clang_cc1 -triple x86_64-netbsd %s -target-feature +avx512f -emit-llvm -o - | FileCheck %s --check-prefixes=CLANG10ABI128,CLANG10ABI256,CLANG10ABI512
@@ -32,8 +32,9 @@ typedef unsigned long long v32u64 __attribute__((vector_size(32)));
3232
typedef unsigned __int128 v32u128 __attribute__((vector_size(32)));
3333

3434
v32u64 test_v32u128(v32u64 a, v32u128 b) {
35-
// MEM256ALIGN16: define{{.*}} <4 x i64> @test_v32u128(ptr noundef byval(<4 x i64>) align 16 %{{.*}}, ptr noundef byval(<2 x i128>) align 16 %{{.*}})
36-
// MEM256ALIGN32: define{{.*}} <4 x i64> @test_v32u128(ptr noundef byval(<4 x i64>) align 32 %{{.*}}, ptr noundef byval(<2 x i128>) align 32 %{{.*}})
35+
// MEMARG256ALIGN16: define{{.*}} <4 x i64> @test_v32u128(ptr noundef byval(<4 x i64>) align 16 %{{.*}}, ptr noundef byval(<2 x i128>) align 16 %{{.*}})
36+
// MEMARG256ALIGN32: define{{.*}} <4 x i64> @test_v32u128(ptr noundef byval(<4 x i64>) align 32 %{{.*}}, ptr noundef byval(<2 x i128>) align 32 %{{.*}})
37+
// MEMRETMEMARG256ALIGN32: define{{.*}} void @test_v32u128(ptr{{.*}} sret(<4 x i64>) align 32 %{{.*}}, ptr noundef byval(<4 x i64>) align 32 %{{.*}}, ptr noundef byval(<2 x i128>) align 32 %{{.*}})
3738
// CLANG10ABI256: define{{.*}} <4 x i64> @test_v32u128(<4 x i64> noundef %{{.*}}, ptr noundef byval(<2 x i128>) align 32 %{{.*}})
3839
// CLANG9ABI256: define{{.*}} <4 x i64> @test_v32u128(<4 x i64> noundef %{{.*}}, <2 x i128> noundef %{{.*}})
3940
return a + (v32u64)b;
@@ -43,9 +44,10 @@ typedef unsigned long long v64u64 __attribute__((vector_size(64)));
4344
typedef unsigned __int128 v64u128 __attribute__((vector_size(64)));
4445

4546
v64u64 test_v64u128(v64u64 a, v64u128 b) {
46-
// MEM512ALIGN16: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 16 %{{.*}}, ptr noundef byval(<4 x i128>) align 16 %{{.*}})
47-
// MEM512ALIGN32: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 32 %{{.*}}, ptr noundef byval(<4 x i128>) align 32 %{{.*}})
48-
// MEM512ALIGN64: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 64 %{{.*}}, ptr noundef byval(<4 x i128>) align 64 %{{.*}})
47+
// MEMARG512ALIGN16: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 16 %{{.*}}, ptr noundef byval(<4 x i128>) align 16 %{{.*}})
48+
// MEMARG512ALIGN32: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 32 %{{.*}}, ptr noundef byval(<4 x i128>) align 32 %{{.*}})
49+
// MEMARG512ALIGN64: define{{.*}} <8 x i64> @test_v64u128(ptr noundef byval(<8 x i64>) align 64 %{{.*}}, ptr noundef byval(<4 x i128>) align 64 %{{.*}})
50+
// MEMRETMEMARG512ALIGN64: define{{.*}} void @test_v64u128(ptr{{.*}} sret(<8 x i64>) align 64 %{{.*}}, ptr noundef byval(<8 x i64>) align 64 %{{.*}}, ptr noundef byval(<4 x i128>) align 64 %{{.*}})
4951
// CLANG10ABI512: define{{.*}} <8 x i64> @test_v64u128(<8 x i64> noundef %{{.*}}, ptr noundef byval(<4 x i128>) align 64 %{{.*}})
5052
// CLANG9ABI512: define{{.*}} <8 x i64> @test_v64u128(<8 x i64> noundef %{{.*}}, <4 x i128> noundef %{{.*}})
5153
return a + (v64u64)b;

0 commit comments

Comments
 (0)