Skip to content

Commit

Permalink
In x86_64, when calling an Objective-C method that returns a _Complex…
Browse files Browse the repository at this point in the history
… long double, make sure to use the objc_msgSend_fp2ret function which ensures that the return value will be {0, 0} if the receiver is nil.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143350 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Anders Carlsson committed Oct 31, 2011
1 parent f453cb9 commit eea6480
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 2 deletions.
2 changes: 2 additions & 0 deletions include/clang/Basic/Builtins.def
Expand Up @@ -698,6 +698,8 @@ LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)

// long double objc_msgSend_fpret(id self, SEL op, ...)
LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG)
// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG)
// id objc_msgSend_stret (id, SEL, ...)
LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG)
// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
Expand Down
7 changes: 7 additions & 0 deletions include/clang/Basic/TargetInfo.h
Expand Up @@ -91,6 +91,7 @@ class TargetInfo : public llvm::RefCountedBase<TargetInfo> {

unsigned HasAlignMac68kSupport : 1;
unsigned RealTypeUsesObjCFPRet : 3;
unsigned ComplexLongDoubleUsesFP2Ret : 1;

// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const std::string &T);
Expand Down Expand Up @@ -327,6 +328,12 @@ class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
return RealTypeUsesObjCFPRet & (1 << T);
}

/// \brief Check whether _Complex long double should use the "fp2ret" flavor
/// of Obj-C message passing on this target.
bool useObjCFP2RetForComplexLongDouble() const {
return ComplexLongDoubleUsesFP2Ret;
}

///===---- Other target property query methods --------------------------===//

/// getTargetDefines - Appends the target-specific #define values for this
Expand Down
3 changes: 3 additions & 0 deletions lib/Basic/TargetInfo.cpp
Expand Up @@ -74,6 +74,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Default to no types using fpret.
RealTypeUsesObjCFPRet = 0;

// Default to not using fp2ret for __Complex long double
ComplexLongDoubleUsesFP2Ret = false;

// Default to using the Itanium ABI.
CXXABI = CXXABI_Itanium;

Expand Down
3 changes: 3 additions & 0 deletions lib/Basic/Targets.cpp
Expand Up @@ -2245,6 +2245,9 @@ class X86_64TargetInfo : public X86TargetInfo {
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);

// Use fp2ret for _Complex long double.
ComplexLongDoubleUsesFP2Ret = true;

// x86-64 has atomics up to 16 bytes.
// FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128
// on CPUs with cmpxchg16b
Expand Down
11 changes: 11 additions & 0 deletions lib/CodeGen/CGCall.cpp
Expand Up @@ -611,6 +611,17 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
return false;
}

bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) {
if (const ComplexType *CT = ResultType->getAs<ComplexType>()) {
if (const BuiltinType *BT = CT->getElementType()->getAs<BuiltinType>()) {
if (BT->getKind() == BuiltinType::LongDouble)
return getContext().getTargetInfo().useObjCFP2RetForComplexLongDouble();
}
}

return false;
}

llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
const CGFunctionInfo &FI = getFunctionInfo(GD);

Expand Down
27 changes: 27 additions & 0 deletions lib/CodeGen/CGObjCMac.cpp
Expand Up @@ -99,6 +99,22 @@ class ObjCCommonTypesHelper {

}

/// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
///
/// The messenger used when the return value is returned in two values on the
/// x87 floating point stack; without a special entrypoint, the nil case
/// would be unbalanced. Only used on 64-bit X86.
llvm::Constant *getMessageSendFp2retFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
llvm::Type *resultType =
llvm::StructType::get(longDoubleType, longDoubleType, NULL);

return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
params, true),
"objc_msgSend_fp2ret");
}

/// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
///
/// The messenger used for super calls, which have different dispatch
Expand Down Expand Up @@ -391,6 +407,14 @@ class ObjCCommonTypesHelper {
return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
}

llvm::Constant *getSendFp2retFn(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
}

llvm::Constant *getSendFp2RetFn2(bool IsSuper) const {
return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
}

ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCCommonTypesHelper(){}
};
Expand Down Expand Up @@ -1590,6 +1614,9 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
: ObjCTypes.getSendFpretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
: ObjCTypes.getSendFp2retFn(IsSuper);
} else {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
Expand Down
8 changes: 6 additions & 2 deletions lib/CodeGen/CodeGenModule.h
Expand Up @@ -715,10 +715,14 @@ class CodeGenModule : public CodeGenTypeCache {
/// as a return type.
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);

/// ReturnTypeUsesSret - Return true iff the given type uses 'fpret' when used
/// as a return type.
/// ReturnTypeUsesFPRet - Return true iff the given type uses 'fpret' when
/// used as a return type.
bool ReturnTypeUsesFPRet(QualType ResultType);

/// ReturnTypeUsesFP2Ret - Return true iff the given type uses 'fp2ret' when
/// used as a return type.
bool ReturnTypeUsesFP2Ret(QualType ResultType);

/// ConstructAttributeList - Get the LLVM attributes and calling convention to
/// use for a particular function type.
///
Expand Down
28 changes: 28 additions & 0 deletions test/CodeGenObjC/fp2ret.m
@@ -0,0 +1,28 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-X86_32 %s
//
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-X86_64 %s
//
// RUN: %clang_cc1 -triple armv7-apple-darwin10 -fobjc-fragile-abi -emit-llvm -target-abi apcs-gnu -o - %s | \
// RUN: FileCheck --check-prefix=CHECK-ARMV7 %s

@interface A
-(_Complex long double) complexLongDoubleValue;
@end


// CHECK-X86_32: define void @t0()
// CHECK-X86_32: call void bitcast {{.*}} @objc_msgSend_stret to
// CHECK-X86_32: }
//
// CHECK-X86_64: define void @t0()
// CHECK-X86_64: call { x86_fp80, x86_fp80 } bitcast {{.*}} @objc_msgSend_fp2ret to
// CHECK-X86_64: }
//
// CHECK-ARMV7: define void @t0()
// CHECK-ARMV7: call i128 bitcast {{.*}} @objc_msgSend to
// CHECK-ARMV7: }
void t0() {
[(A*)0 complexLongDoubleValue];
}

0 comments on commit eea6480

Please sign in to comment.