Skip to content

Commit 4fe7ea5

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 4fe7ea5

File tree

4 files changed

+81
-21
lines changed

4 files changed

+81
-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: 37 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,17 @@ 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+
1351+
13371352
X86AVXABILevel AVXLevel;
13381353
// Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
13391354
// 64-bit hardware.
@@ -2156,9 +2171,12 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
21562171
}
21572172

21582173
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
2174+
const bool returnIllegalVectorsIndirectly = (returnIllegalVectorsInMem() &&
2175+
IsIllegalReturnVectorType(Ty));
2176+
21592177
// If this is a scalar LLVM value then assume LLVM will pass it in the right
21602178
// place naturally.
2161-
if (!isAggregateTypeForABI(Ty)) {
2179+
if (!isAggregateTypeForABI(Ty) && !returnIllegalVectorsIndirectly) {
21622180
// Treat an enum type as its underlying type.
21632181
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
21642182
Ty = EnumTy->getDecl()->getIntegerType();
@@ -2173,12 +2191,24 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
21732191
return getNaturalAlignIndirect(Ty);
21742192
}
21752193

2176-
bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
2194+
static bool IsIllegalVector(QualType Ty,
2195+
uint64_t Size,
2196+
X86AVXABILevel AVXLevel) {
21772197
if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
2178-
uint64_t Size = getContext().getTypeSize(VecTy);
21792198
unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel);
21802199
if (Size <= 64 || Size > LargestVector)
21812200
return true;
2201+
}
2202+
2203+
return false;
2204+
}
2205+
2206+
bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
2207+
if (IsIllegalVector(Ty, getContext().getTypeSize(Ty), AVXLevel))
2208+
return true;
2209+
2210+
// Maintain backward compatibility
2211+
if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
21822212
QualType EltTy = VecTy->getElementType();
21832213
if (passInt128VectorsInMem() &&
21842214
(EltTy->isSpecificBuiltinType(BuiltinType::Int128) ||
@@ -2189,6 +2219,10 @@ bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
21892219
return false;
21902220
}
21912221

2222+
bool X86_64ABIInfo::IsIllegalReturnVectorType(QualType Ty) const {
2223+
return IsIllegalVector(Ty, getContext().getTypeSize(Ty), AVXLevel);
2224+
}
2225+
21922226
ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
21932227
unsigned freeIntRegs) const {
21942228
// 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)