Skip to content

Commit 1b0a71c

Browse files
committed
[PowerPC][AIX] Add support for varargs for complex types on AIX
Remove the previous error and add support for special handling of small complex types as in PPC64 ELF ABI. As in, generate code to load from varargs location and pack it in a temp variable, then return a pointer to the struct. Reviewed By: sfertile Differential Revision: https://reviews.llvm.org/D106393
1 parent d9fc3d8 commit 1b0a71c

File tree

3 files changed

+112
-29
lines changed

3 files changed

+112
-29
lines changed

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,36 @@ static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
392392

393393
}
394394

395+
static Address complexTempStructure(CodeGenFunction &CGF, Address VAListAddr,
396+
QualType Ty, CharUnits SlotSize,
397+
CharUnits EltSize, const ComplexType *CTy) {
398+
Address Addr =
399+
emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, SlotSize * 2,
400+
SlotSize, SlotSize, /*AllowHigher*/ true);
401+
402+
Address RealAddr = Addr;
403+
Address ImagAddr = RealAddr;
404+
if (CGF.CGM.getDataLayout().isBigEndian()) {
405+
RealAddr =
406+
CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize - EltSize);
407+
ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr,
408+
2 * SlotSize - EltSize);
409+
} else {
410+
ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize);
411+
}
412+
413+
llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType());
414+
RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy);
415+
ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy);
416+
llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal");
417+
llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag");
418+
419+
Address Temp = CGF.CreateMemTemp(Ty, "vacplx");
420+
CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty),
421+
/*init*/ true);
422+
return Temp;
423+
}
424+
395425
static Address emitMergePHI(CodeGenFunction &CGF,
396426
Address Addr1, llvm::BasicBlock *Block1,
397427
Address Addr2, llvm::BasicBlock *Block2,
@@ -4631,14 +4661,25 @@ CharUnits AIXABIInfo::getParamTypeAlignment(QualType Ty) const {
46314661

46324662
Address AIXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
46334663
QualType Ty) const {
4634-
if (Ty->isAnyComplexType())
4635-
llvm::report_fatal_error("complex type is not supported on AIX yet");
46364664

46374665
auto TypeInfo = getContext().getTypeInfoInChars(Ty);
46384666
TypeInfo.Align = getParamTypeAlignment(Ty);
46394667

46404668
CharUnits SlotSize = CharUnits::fromQuantity(PtrByteSize);
46414669

4670+
// If we have a complex type and the base type is smaller than the register
4671+
// size, the ABI calls for the real and imaginary parts to be right-adjusted
4672+
// in separate words in 32bit mode or doublewords in 64bit mode. However,
4673+
// Clang expects us to produce a pointer to a structure with the two parts
4674+
// packed tightly. So generate loads of the real and imaginary parts relative
4675+
// to the va_list pointer, and store them to a temporary structure. We do the
4676+
// same as the PPC64ABI here.
4677+
if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
4678+
CharUnits EltSize = TypeInfo.Width / 2;
4679+
if (EltSize < SlotSize)
4680+
return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy);
4681+
}
4682+
46424683
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo,
46434684
SlotSize, /*AllowHigher*/ true);
46444685
}
@@ -5406,33 +5447,8 @@ Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
54065447
// and store them to a temporary structure.
54075448
if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
54085449
CharUnits EltSize = TypeInfo.Width / 2;
5409-
if (EltSize < SlotSize) {
5410-
Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty,
5411-
SlotSize * 2, SlotSize,
5412-
SlotSize, /*AllowHigher*/ true);
5413-
5414-
Address RealAddr = Addr;
5415-
Address ImagAddr = RealAddr;
5416-
if (CGF.CGM.getDataLayout().isBigEndian()) {
5417-
RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr,
5418-
SlotSize - EltSize);
5419-
ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr,
5420-
2 * SlotSize - EltSize);
5421-
} else {
5422-
ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize);
5423-
}
5424-
5425-
llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType());
5426-
RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy);
5427-
ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy);
5428-
llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal");
5429-
llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag");
5430-
5431-
Address Temp = CGF.CreateMemTemp(Ty, "vacplx");
5432-
CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty),
5433-
/*init*/ true);
5434-
return Temp;
5435-
}
5450+
if (EltSize < SlotSize)
5451+
return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy);
54365452
}
54375453

54385454
// Otherwise, just use the general rule.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// REQUIRES: powerpc-registered-target
2+
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -emit-llvm -o - %s | FileCheck %s
3+
4+
#include <stdarg.h>
5+
6+
void testva (int n, ...)
7+
{
8+
va_list ap;
9+
10+
_Complex int i = va_arg(ap, _Complex int);
11+
// CHECK: %[[VAR40:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
12+
// CHECK-NEXT: %[[VAR41:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR40]]
13+
// CHECK-NEXT: store i8* %[[VAR41]], i8** %[[VAR100]], align 4
14+
// CHECK-NEXT: %[[VAR4:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR40]] to { i32, i32 }*
15+
// CHECK-NEXT: %[[VAR6:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VAR4]], i32 0, i32 0
16+
// CHECK-NEXT: %[[VAR7:[A-Za-z0-9.]+]] = load i32, i32* %[[VAR6]]
17+
// CHECK-NEXT: %[[VAR8:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VAR4]], i32 0, i32 1
18+
// CHECK-NEXT: %[[VAR9:[A-Za-z0-9.]+]] = load i32, i32* %[[VAR8]]
19+
// CHECK-NEXT: %[[VAR10:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VARINT:[A-Za-z0-9.]+]], i32 0, i32 0
20+
// CHECK-NEXT: %[[VAR11:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VARINT]], i32 0, i32 1
21+
// CHECK-NEXT: store i32 %[[VAR7]], i32* %[[VAR10]]
22+
// CHECK-NEXT: store i32 %[[VAR9]], i32* %[[VAR11]]
23+
24+
_Complex short s = va_arg(ap, _Complex short);
25+
// CHECK: %[[VAR50:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
26+
// CHECK-NEXT: %[[VAR51:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]]
27+
// CHECK-NEXT: store i8* %[[VAR51]], i8** %[[VAR100]], align 4
28+
// CHECK-NEXT: %[[VAR12:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]], i32 2
29+
// CHECK-NEXT: %[[VAR13:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]], i32 6
30+
// CHECK-NEXT: %[[VAR14:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR12]] to i16*
31+
// CHECK-NEXT: %[[VAR15:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR13]] to i16*
32+
// CHECK-NEXT: %[[VAR16:[A-Za-z0-9.]+]] = load i16, i16* %[[VAR14]], align 2
33+
// CHECK-NEXT: %[[VAR17:[A-Za-z0-9.]+]] = load i16, i16* %[[VAR15]], align 2
34+
// CHECK-NEXT: %[[VAR18:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }, { i16, i16 }* %[[VAR19:[A-Za-z0-9.]+]], i32 0, i32 0
35+
// CHECK-NEXT: %[[VAR20:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }, { i16, i16 }* %[[VAR19]], i32 0, i32 1
36+
// CHECK-NEXT: store i16 %[[VAR16]], i16* %[[VAR18]]
37+
// CHECK-NEXT: store i16 %[[VAR17]], i16* %[[VAR20]]
38+
39+
40+
_Complex char c = va_arg(ap, _Complex char);
41+
// CHECK: %[[VAR60:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
42+
// CHECK-NEXT: %[[VAR61:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]]
43+
// CHECK-NEXT: store i8* %[[VAR61]], i8** %[[VAR100]], align 4
44+
// CHECK-NEXT: %[[VAR21:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]], i32 3
45+
// CHECK-NEXT: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]], i32 7
46+
// CHECK-NEXT: %[[VAR23:[A-Za-z0-9.]+]] = load i8, i8* %[[VAR21]]
47+
// CHECK-NEXT: %[[VAR24:[A-Za-z0-9.]+]] = load i8, i8* %[[VAR22]]
48+
// CHECK-NEXT: %[[VAR25:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }, { i8, i8 }* %[[VAR26:[A-Za-z0-9.]+]], i32 0, i32 0
49+
// CHECK-NEXT: %[[VAR27:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }, { i8, i8 }* %[[VAR26]], i32 0, i32 1
50+
// CHECK-NEXT: store i8 %[[VAR23]], i8* %[[VAR25]]
51+
// CHECK-NEXT: store i8 %[[VAR24]], i8* %[[VAR27]]
52+
53+
54+
_Complex float f = va_arg(ap, _Complex float);
55+
// CHECK: %[[VAR70:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR71:[A-Za-z0-9.]+]], i32 8
56+
// CHECK-NEXT: store i8* %[[VAR70]], i8** %[[VAR100:[A-Za-z0-9.]+]]
57+
// CHECK-NEXT: %[[VAR28:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR71]] to { float, float }*
58+
// CHECK-NEXT: %[[VAR29:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %[[VAR28]], i32 0, i32 0
59+
// CHECK-NEXT: %[[VAR30:[A-Za-z0-9.]+]] = load float, float* %[[VAR29]]
60+
// CHECK-NEXT: %[[VAR31:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %[[VAR28]], i32 0, i32 1
61+
// CHECK-NEXT: %[[VAR32:[A-Za-z0-9.]+]] = load float, float* %[[VAR31]]
62+
// CHECK-NEXT: %[[VAR33:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %f, i32 0, i32 0
63+
// CHECK-NEXT: %[[VAR34:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %f, i32 0, i32 1
64+
// CHECK-NEXT: store float %[[VAR30]], float* %[[VAR33]]
65+
// CHECK-NEXT: store float %[[VAR32]], float* %[[VAR34]]
66+
}

clang/test/CodeGen/ppc64-varargs-complex.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// REQUIRES: powerpc-registered-target
22
// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -o - %s | FileCheck %s
34

45
#include <stdarg.h>
56

0 commit comments

Comments
 (0)