From: Eli Friedman Date: Fri, 2 Dec 2011 00:11:43 +0000 (+0000) Subject: When we're passing a vector with an illegal type through memory on x86-64, use byval... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee1ad99f1ced9ffee436466ef674d4541c37864e;p=clang When we're passing a vector with an illegal type through memory on x86-64, use byval so we're sure the backend does the right thing. Fixes va_arg with illegal vectors and an obscure ABI mismatch with __m64 vectors. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145652 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 404160bc4f..4eaa6248e2 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -1347,7 +1347,11 @@ public: virtual void getDefaultFeatures(llvm::StringMap &Features) const; virtual void HandleTargetFeatures(std::vector &Features); virtual const char* getABI() const { - return MMX3DNowLevel == NoMMX3DNow ? "no-mmx" : ""; + if (PointerWidth == 64 && HasAVX) + return "avx"; + else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow) + return "no-mmx"; + return ""; } virtual bool setCPU(const std::string &Name) { CPU = llvm::StringSwitch(Name) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 77c4c9b07e..16d22dd53c 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -917,6 +917,8 @@ class X86_64ABIInfo : public ABIInfo { unsigned &neededInt, unsigned &neededSSE) const; + bool IsIllegalVectorType(QualType Ty) const; + /// The 0.98 ABI revision clarified a lot of ambiguities, /// unfortunately in ways that were not always consistent with /// certain previous compilers. In particular, platforms which @@ -926,8 +928,11 @@ class X86_64ABIInfo : public ABIInfo { return !getContext().getTargetInfo().getTriple().isOSDarwin(); } + bool HasAVX; + public: - X86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) : + ABIInfo(CGT), HasAVX(hasavx) {} virtual void computeInfo(CGFunctionInfo &FI) const; @@ -951,8 +956,8 @@ public: class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: - X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) - : TargetCodeGenInfo(new X86_64ABIInfo(CGT)) {} + X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX) + : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { return 7; @@ -1194,7 +1199,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // split. if (OffsetBase && OffsetBase != 64) Hi = Lo; - } else if (Size == 128 || Size == 256) { + } else if (Size == 128 || (HasAVX && Size == 256)) { // Arguments of 256-bits are split into four eightbyte chunks. The // least significant one belongs to class SSE and all the others to class // SSEUP. The original Lo and Hi design considers that types can't be @@ -1407,10 +1412,21 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { return ABIArgInfo::getIndirect(0); } +bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const { + if (const VectorType *VecTy = Ty->getAs()) { + uint64_t Size = getContext().getTypeSize(VecTy); + unsigned LargestVector = HasAVX ? 256 : 128; + if (Size <= 64 || Size > LargestVector) + return true; + } + + return false; +} + ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. - if (!isAggregateTypeForABI(Ty)) { + if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -3373,14 +3389,18 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { } } - case llvm::Triple::x86_64: + case llvm::Triple::x86_64: { + bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0; + switch (Triple.getOS()) { case llvm::Triple::Win32: case llvm::Triple::MinGW32: case llvm::Triple::Cygwin: return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types)); default: - return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types)); + return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types, + HasAVX)); } } + } } diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 7072886780..8e7119ef2c 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s| FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -target-feature +avx | FileCheck %s -check-prefix=AVX #include // CHECK: define signext i8 @f0() @@ -263,8 +264,10 @@ void f9122143() typedef unsigned v2i32 __attribute((__vector_size__(8))); v2i32 f36(v2i32 arg) { return arg; } -// CHECK: declare void @f38(<8 x float>) -// CHECK: declare void @f37(<8 x float>) +// AVX: declare void @f38(<8 x float>) +// AVX: declare void @f37(<8 x float>) +// CHECK: declare void @f38(%struct.s256* byval align 32) +// CHECK: declare void @f37(<8 x float>* byval align 32) typedef float __m256 __attribute__ ((__vector_size__ (32))); typedef struct { __m256 m; @@ -320,7 +323,7 @@ int f44(int i, ...) { } // Text that vec3 returns the correct LLVM IR type. -// CHECK: define i32 @foo(<3 x i64> %X) +// AVX: define i32 @foo(<3 x i64> %X) typedef long long3 __attribute((ext_vector_type(3))); int foo(long3 X) { @@ -329,8 +332,16 @@ int foo(long3 X) // Make sure we don't use a varargs convention for a function without a // prototype where AVX types are involved. -// CHECK: @test45 -// CHECK: call i32 bitcast (i32 (...)* @f45 to i32 (<8 x float>)*) +// AVX: @test45 +// AVX: call i32 bitcast (i32 (...)* @f45 to i32 (<8 x float>)*) int f45(); __m256 x45; void test45() { f45(x45); } + +// Make sure we use byval to pass 64-bit vectors in memory; the LLVM call +// lowering can't handle this case correctly because it runs after legalization. +// CHECK: @test46 +// CHECK: call void @f46({{.*}}<2 x float>* byval align 8 {{.*}}, <2 x float>* byval align 8 {{.*}}) +typedef float v46 __attribute((vector_size(8))); +void f46(v46,v46,v46,v46,v46,v46,v46,v46,v46,v46); +void test46() { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }