Skip to content

Commit 26cfb6e

Browse files
committed
[X86] Passing union type through register
For example: union M256 { double d; __m256 m; }; extern void foo1(union M256 A); union M256 m1; void test() { foo1(m1); } clang will pass m1 through stack which does not follow the ABI. Differential Revision: https://reviews.llvm.org/D78699
1 parent c1489ee commit 26cfb6e

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,6 +3061,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
30613061

30623062
// Classify the fields one at a time, merging the results.
30633063
unsigned idx = 0;
3064+
bool IsUnion = RT->isUnionType();
30643065
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
30653066
i != e; ++i, ++idx) {
30663067
uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
@@ -3071,14 +3072,17 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
30713072
continue;
30723073

30733074
// AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger than
3074-
// four eightbytes, or it contains unaligned fields, it has class MEMORY.
3075+
// eight eightbytes, or it contains unaligned fields, it has class MEMORY.
30753076
//
3076-
// The only case a 256-bit wide vector could be used is when the struct
3077-
// contains a single 256-bit element. Since Lo and Hi logic isn't extended
3078-
// to work for sizes wider than 128, early check and fallback to memory.
3077+
// The only case a 256-bit or a 512-bit wide vector could be used is when
3078+
// the struct contains a single 256-bit or 512-bit element. Early check
3079+
// and fallback to memory.
30793080
//
3080-
if (Size > 128 && (Size != getContext().getTypeSize(i->getType()) ||
3081-
Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
3081+
// FIXME: Extended the Lo and Hi logic properly to work for size wider
3082+
// than 128.
3083+
if (Size > 128 &&
3084+
((!IsUnion && Size != getContext().getTypeSize(i->getType())) ||
3085+
Size > getNativeVectorSizeForAVXABI(AVXLevel))) {
30823086
Lo = Memory;
30833087
postMerge(Size, Lo, Hi);
30843088
return;

clang/test/CodeGen/X86/avx-union.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx -emit-llvm -o %t %s || FileCheck < %t %s --check-prefix=CHECK, AVX
2+
// RUN: %clang_cc1 -w -ffreestanding -triple x86_64-linux-gnu -target-feature +avx512f -emit-llvm -o %t %s || FileCheck < %t %s --check-prefix=CHECK, AVX512
3+
// This tests verifies that a union parameter should pass by a vector regitster whose first eightbyte is SSE and the other eightbytes are SSEUP.
4+
5+
typedef int __m256 __attribute__ ((__vector_size__ (32)));
6+
typedef int __m512 __attribute__ ((__vector_size__ (64)));
7+
8+
union M256 {
9+
double d;
10+
__m256 m;
11+
};
12+
13+
union M512 {
14+
double d;
15+
__m512 m;
16+
};
17+
18+
extern void foo1(union M256 A);
19+
extern void foo2(union M512 A);
20+
union M256 m1;
21+
union M512 m2;
22+
// CHECK-LABEL: define dso_local void @test()
23+
// CHECK: void @foo1(<4 x double>
24+
// AVX: call void @foo2(%union.M512* byval(%union.M512) align 64
25+
// AVX512: call void @foo2(<8 x double>
26+
void test() {
27+
foo1(m1);
28+
foo2(m2);
29+
}

0 commit comments

Comments
 (0)