From 90b22c9de6bed50f9954ea154248a69ab6261d78 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Tue, 27 Nov 2012 02:46:43 +0000 Subject: [PATCH] This patch addresses an incompatibility relative to the 64-bit PowerPC ELF ABI. Complex values are to be passed in registers as though the real and imaginary parts were passed as separate parameters. Prior to this patch, complex values were passed as byval aggregates. It turns out that specifying getDirect() for all complex types when classifying the argument type results in the desired behavior. The new Clang test case verifies that the correct LLVM IR is generated for caller and callee for each of the underlying types for _Complex. llvm-svn: 168673 --- clang/lib/CodeGen/TargetInfo.cpp | 3 + clang/test/CodeGen/ppc64-complex-parms.c | 182 +++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 clang/test/CodeGen/ppc64-complex-parms.c diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 4cff081..1582eb6 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -2777,6 +2777,9 @@ PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { ABIArgInfo PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { + if (Ty->isAnyComplexType()) + return ABIArgInfo::getDirect(); + if (isAggregateTypeForABI(Ty)) { // Records with non trivial destructors/constructors should not be passed // by value. diff --git a/clang/test/CodeGen/ppc64-complex-parms.c b/clang/test/CodeGen/ppc64-complex-parms.c new file mode 100644 index 0000000..0c41d8c --- /dev/null +++ b/clang/test/CodeGen/ppc64-complex-parms.c @@ -0,0 +1,182 @@ +// REQUIRES: ppc64-registered-target +// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +float crealf(_Complex float); +double creal(_Complex double); +long double creall(_Complex long double); + +float foo_float(_Complex float x) { + return crealf(x); +} + +// CHECK: define float @foo_float(float {{[%A-Za-z0-9.]+}}, float {{[%A-Za-z0-9.]+}}) nounwind { + +double foo_double(_Complex double x) { + return creal(x); +} + +// CHECK: define double @foo_double(double {{[%A-Za-z0-9.]+}}, double {{[%A-Za-z0-9.]+}}) nounwind { + +long double foo_long_double(_Complex long double x) { + return creall(x); +} + +// CHECK: define ppc_fp128 @foo_long_double(ppc_fp128 {{[%A-Za-z0-9.]+}}, ppc_fp128 {{[%A-Za-z0-9.]+}}) nounwind { + +int foo_int(_Complex int x) { + return __real__ x; +} + +// CHECK: define signext i32 @foo_int(i32 {{[%A-Za-z0-9.]+}}, i32 {{[%A-Za-z0-9.]+}}) nounwind { + +short foo_short(_Complex short x) { + return __real__ x; +} + +// CHECK: define signext i16 @foo_short(i16 {{[%A-Za-z0-9.]+}}, i16 {{[%A-Za-z0-9.]+}}) nounwind { + +signed char foo_char(_Complex signed char x) { + return __real__ x; +} + +// CHECK: define signext i8 @foo_char(i8 {{[%A-Za-z0-9.]+}}, i8 {{[%A-Za-z0-9.]+}}) nounwind { + +long foo_long(_Complex long x) { + return __real__ x; +} + +// CHECK: define i64 @foo_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) nounwind { + +long long foo_long_long(_Complex long long x) { + return __real__ x; +} + +// CHECK: define i64 @foo_long_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) nounwind { + +void bar_float(void) { + foo_float(2.0f - 2.5fi); +} + +// CHECK: define void @bar_float() nounwind { +// CHECK: %[[VAR1:[A-Za-z0-9.]+]] = alloca { float, float }, align 4 +// CHECK: %[[VAR2:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR1]], i32 0, i32 0 +// CHECK: %[[VAR3:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR1]], i32 0, i32 1 +// CHECK: store float 2.000000e+00, float* %[[VAR2]] +// CHECK: store float -2.500000e+00, float* %[[VAR3]] +// CHECK: %[[VAR4:[A-Za-z0-9.]+]] = getelementptr { float, float }* %[[VAR1]], i32 0, i32 0 +// CHECK: %[[VAR5:[A-Za-z0-9.]+]] = load float* %[[VAR4]], align 1 +// CHECK: %[[VAR6:[A-Za-z0-9.]+]] = getelementptr { float, float }* %[[VAR1]], i32 0, i32 1 +// CHECK: %[[VAR7:[A-Za-z0-9.]+]] = load float* %[[VAR6]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call float @foo_float(float %[[VAR5]], float %[[VAR7]]) + +void bar_double(void) { + foo_double(2.0 - 2.5i); +} + +// CHECK: define void @bar_double() nounwind { +// CHECK: %[[VAR11:[A-Za-z0-9.]+]] = alloca { double, double }, align 8 +// CHECK: %[[VAR12:[A-Za-z0-9.]+]] = getelementptr inbounds { double, double }* %[[VAR11]], i32 0, i32 0 +// CHECK: %[[VAR13:[A-Za-z0-9.]+]] = getelementptr inbounds { double, double }* %[[VAR11]], i32 0, i32 1 +// CHECK: store double 2.000000e+00, double* %[[VAR12]] +// CHECK: store double -2.500000e+00, double* %[[VAR13]] +// CHECK: %[[VAR14:[A-Za-z0-9.]+]] = getelementptr { double, double }* %[[VAR11]], i32 0, i32 0 +// CHECK: %[[VAR15:[A-Za-z0-9.]+]] = load double* %[[VAR14]], align 1 +// CHECK: %[[VAR16:[A-Za-z0-9.]+]] = getelementptr { double, double }* %[[VAR11]], i32 0, i32 1 +// CHECK: %[[VAR17:[A-Za-z0-9.]+]] = load double* %[[VAR16]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call double @foo_double(double %[[VAR15]], double %[[VAR17]]) + +void bar_long_double(void) { + foo_long_double(2.0L - 2.5Li); +} + +// CHECK: define void @bar_long_double() nounwind { +// CHECK: %[[VAR21:[A-Za-z0-9.]+]] = alloca { ppc_fp128, ppc_fp128 }, align 16 +// CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0 +// CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1 +// CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]] +// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]] +// CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0 +// CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128* %[[VAR24]], align 1 +// CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1 +// CHECK: %[[VAR27:[A-Za-z0-9.]+]] = load ppc_fp128* %[[VAR26]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call ppc_fp128 @foo_long_double(ppc_fp128 %[[VAR25]], ppc_fp128 %[[VAR27]]) + +void bar_int(void) { + foo_int(2 - 3i); +} + +// CHECK: define void @bar_int() nounwind { +// CHECK: %[[VAR31:[A-Za-z0-9.]+]] = alloca { i32, i32 }, align 4 +// CHECK: %[[VAR32:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR31]], i32 0, i32 0 +// CHECK: %[[VAR33:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR31]], i32 0, i32 1 +// CHECK: store i32 2, i32* %[[VAR32]] +// CHECK: store i32 -3, i32* %[[VAR33]] +// CHECK: %[[VAR34:[A-Za-z0-9.]+]] = getelementptr { i32, i32 }* %[[VAR31]], i32 0, i32 0 +// CHECK: %[[VAR35:[A-Za-z0-9.]+]] = load i32* %[[VAR34]], align 1 +// CHECK: %[[VAR36:[A-Za-z0-9.]+]] = getelementptr { i32, i32 }* %[[VAR31]], i32 0, i32 1 +// CHECK: %[[VAR37:[A-Za-z0-9.]+]] = load i32* %[[VAR36]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call signext i32 @foo_int(i32 %[[VAR35]], i32 %[[VAR37]]) + +void bar_short(void) { + foo_short(2 - 3i); +} + +// CHECK: define void @bar_short() nounwind { +// CHECK: %[[VAR41:[A-Za-z0-9.]+]] = alloca { i16, i16 }, align 2 +// CHECK: %[[VAR42:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR41]], i32 0, i32 0 +// CHECK: %[[VAR43:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR41]], i32 0, i32 1 +// CHECK: store i16 2, i16* %[[VAR42]] +// CHECK: store i16 -3, i16* %[[VAR43]] +// CHECK: %[[VAR44:[A-Za-z0-9.]+]] = getelementptr { i16, i16 }* %[[VAR41]], i32 0, i32 0 +// CHECK: %[[VAR45:[A-Za-z0-9.]+]] = load i16* %[[VAR44]], align 1 +// CHECK: %[[VAR46:[A-Za-z0-9.]+]] = getelementptr { i16, i16 }* %[[VAR41]], i32 0, i32 1 +// CHECK: %[[VAR47:[A-Za-z0-9.]+]] = load i16* %[[VAR46]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call signext i16 @foo_short(i16 %[[VAR45]], i16 %[[VAR47]]) + +void bar_char(void) { + foo_char(2 - 3i); +} + +// CHECK: define void @bar_char() nounwind { +// CHECK: %[[VAR51:[A-Za-z0-9.]+]] = alloca { i8, i8 }, align 1 +// CHECK: %[[VAR52:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR51]], i32 0, i32 0 +// CHECK: %[[VAR53:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR51]], i32 0, i32 1 +// CHECK: store i8 2, i8* %[[VAR52]] +// CHECK: store i8 -3, i8* %[[VAR53]] +// CHECK: %[[VAR54:[A-Za-z0-9.]+]] = getelementptr { i8, i8 }* %[[VAR51]], i32 0, i32 0 +// CHECK: %[[VAR55:[A-Za-z0-9.]+]] = load i8* %[[VAR54]], align 1 +// CHECK: %[[VAR56:[A-Za-z0-9.]+]] = getelementptr { i8, i8 }* %[[VAR51]], i32 0, i32 1 +// CHECK: %[[VAR57:[A-Za-z0-9.]+]] = load i8* %[[VAR56]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call signext i8 @foo_char(i8 %[[VAR55]], i8 %[[VAR57]]) + +void bar_long(void) { + foo_long(2L - 3Li); +} + +// CHECK: define void @bar_long() nounwind { +// CHECK: %[[VAR61:[A-Za-z0-9.]+]] = alloca { i64, i64 }, align 8 +// CHECK: %[[VAR62:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR61]], i32 0, i32 0 +// CHECK: %[[VAR63:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR61]], i32 0, i32 1 +// CHECK: store i64 2, i64* %[[VAR62]] +// CHECK: store i64 -3, i64* %[[VAR63]] +// CHECK: %[[VAR64:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR61]], i32 0, i32 0 +// CHECK: %[[VAR65:[A-Za-z0-9.]+]] = load i64* %[[VAR64]], align 1 +// CHECK: %[[VAR66:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR61]], i32 0, i32 1 +// CHECK: %[[VAR67:[A-Za-z0-9.]+]] = load i64* %[[VAR66]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call i64 @foo_long(i64 %[[VAR65]], i64 %[[VAR67]]) + +void bar_long_long(void) { + foo_long_long(2LL - 3LLi); +} + +// CHECK: define void @bar_long_long() nounwind { +// CHECK: %[[VAR71:[A-Za-z0-9.]+]] = alloca { i64, i64 }, align 8 +// CHECK: %[[VAR72:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR71]], i32 0, i32 0 +// CHECK: %[[VAR73:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR71]], i32 0, i32 1 +// CHECK: store i64 2, i64* %[[VAR72]] +// CHECK: store i64 -3, i64* %[[VAR73]] +// CHECK: %[[VAR74:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR71]], i32 0, i32 0 +// CHECK: %[[VAR75:[A-Za-z0-9.]+]] = load i64* %[[VAR74]], align 1 +// CHECK: %[[VAR76:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR71]], i32 0, i32 1 +// CHECK: %[[VAR77:[A-Za-z0-9.]+]] = load i64* %[[VAR76]], align 1 +// CHECK: %{{[A-Za-z0-9.]+}} = call i64 @foo_long_long(i64 %[[VAR75]], i64 %[[VAR77]]) -- 2.7.4