CodeGen/ObjC/NeXT: Fix Obj-C message send to match llvm-gcc when choosing
whether to use objc_msgSend_fpret; the choice is target dependent, not Obj-C ABI
dependent.
- <rdar://problem/8139758> arm objc _objc_msgSend_fpret bug
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108379 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 5763a12..9f7debf 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -61,6 +61,7 @@
std::string CXXABI;
unsigned HasAlignMac68kSupport : 1;
+ unsigned RealTypeUsesObjCFPRet : 3;
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const std::string &T);
@@ -87,6 +88,13 @@
SignedLongLong,
UnsignedLongLong
};
+
+ enum RealType {
+ Float = 0,
+ Double,
+ LongDouble
+ };
+
protected:
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType;
@@ -233,6 +241,12 @@
/// integer type enum. For example, SignedLong -> "L".
static const char *getTypeConstantSuffix(IntType T);
+ /// \brief Check whether the given real type should use the "fpret" flavor of
+ /// Obj-C message passing on this target.
+ bool useObjCFPRetForRealType(RealType T) const {
+ return RealTypeUsesObjCFPRet & (1 << T);
+ }
+
///===---- Other target property query methods --------------------------===//
/// getTargetDefines - Appends the target-specific #define values for this
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index e4eaf63..7fcf372 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -55,6 +55,9 @@
"i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
HasAlignMac68kSupport = false;
+
+ // Default to no types using fpret.
+ RealTypeUsesObjCFPRet = 0;
}
// Out of line virtual dtor for TargetInfo.
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 8d79316..fdf63e7 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1245,6 +1245,11 @@
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
RegParmMax = 3;
+
+ // Use fpret for all types.
+ RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
+ (1 << TargetInfo::Double) |
+ (1 << TargetInfo::LongDouble));
}
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -1411,6 +1416,9 @@
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
"a0:0:64-s0:64:64-f80:128:128-n8:16:32:64";
+
+ // Use fpret only for long double.
+ RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
}
virtual const char *getVAListDeclaration() const {
return "typedef struct __va_list_tag {"
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 0d05a62..cb9e636 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -253,7 +253,7 @@
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args,
FunctionType::ExtInfo());
- if (CGM.ReturnTypeUsesSret(FnInfo))
+ if (CGM.ReturnTypeUsesSRet(FnInfo))
flags |= BLOCK_USE_STRET;
}
const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 1632cb3..3d1e143 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -564,10 +564,28 @@
/***/
-bool CodeGenModule::ReturnTypeUsesSret(const CGFunctionInfo &FI) {
+bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) {
return FI.getReturnInfo().isIndirect();
}
+bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
+ if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ default:
+ return false;
+ case BuiltinType::Float:
+ return getContext().Target.useObjCFPRetForRealType(TargetInfo::Float);
+ case BuiltinType::Double:
+ return getContext().Target.useObjCFPRetForRealType(TargetInfo::Double);
+ case BuiltinType::LongDouble:
+ return getContext().Target.useObjCFPRetForRealType(
+ TargetInfo::LongDouble);
+ }
+ }
+
+ return false;
+}
+
const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
const CGFunctionInfo &FI = getFunctionInfo(GD);
@@ -841,7 +859,7 @@
llvm::Function::arg_iterator AI = Fn->arg_begin();
// Name the struct return argument.
- if (CGM.ReturnTypeUsesSret(FI)) {
+ if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
++AI;
}
@@ -1116,7 +1134,7 @@
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
- if (CGM.ReturnTypeUsesSret(CallInfo)) {
+ if (CGM.ReturnTypeUsesSRet(CallInfo)) {
llvm::Value *Value = ReturnValue.getValue();
if (!Value)
Value = CreateMemTemp(RetTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2992867..01ead9e 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1650,29 +1650,17 @@
"Result type mismatch!");
llvm::Constant *Fn = NULL;
- if (CGM.ReturnTypeUsesSret(FnInfo)) {
+ if (CGM.ReturnTypeUsesSRet(FnInfo)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
- } else if (ResultType->isRealFloatingType()) {
- if (ObjCABI == 2) {
- if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
- BuiltinType::Kind k = BT->getKind();
- Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper)
- : ObjCTypes.getSendFn2(IsSuper);
- } else {
- Fn = ObjCTypes.getSendFn2(IsSuper);
- }
- } else
- // FIXME. This currently matches gcc's API for x86-32. May need to change
- // for others if we have their API.
- Fn = ObjCTypes.getSendFpretFn(IsSuper);
+ } else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
+ Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
+ : ObjCTypes.getSendFpretFn(IsSuper);
} else {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
- assert(Fn && "EmitLegacyMessageSend - unknown API");
- Fn = llvm::ConstantExpr::getBitCast(Fn,
- llvm::PointerType::getUnqual(FTy));
+ Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
}
@@ -5295,7 +5283,7 @@
FunctionType::ExtInfo());
llvm::Constant *Fn = 0;
std::string Name("\01l_");
- if (CGM.ReturnTypeUsesSret(FnInfo)) {
+ if (CGM.ReturnTypeUsesSRet(FnInfo)) {
#if 0
// unlike what is documented. gcc never generates this API!!
if (Receiver->getType() == ObjCTypes.ObjectPtrTy) {
@@ -5312,14 +5300,9 @@
Fn = ObjCTypes.getMessageSendStretFixupFn();
Name += "objc_msgSend_stret_fixup";
}
- } else if (!IsSuper && ResultType->isRealFloatingType()) {
- if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) {
- Fn = ObjCTypes.getMessageSendFpretFixupFn();
- Name += "objc_msgSend_fpret_fixup";
- } else {
- Fn = ObjCTypes.getMessageSendFixupFn();
- Name += "objc_msgSend_fixup";
- }
+ } else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) {
+ Fn = ObjCTypes.getMessageSendFpretFixupFn();
+ Name += "objc_msgSend_fpret_fixup";
} else {
#if 0
// unlike what is documented. gcc never generates this API!!
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index a1ea0ec..27f15fc 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -444,9 +444,13 @@
/// which only apply to a function definintion.
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
- /// ReturnTypeUsesSret - Return true iff the given type uses 'sret' when used
+ /// ReturnTypeUsesSRet - Return true iff the given type uses 'sret' when used
/// as a return type.
- bool ReturnTypeUsesSret(const CGFunctionInfo &FI);
+ bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
+
+ /// ReturnTypeUsesSret - Return true iff the given type uses 'fpret' when used
+ /// as a return type.
+ bool ReturnTypeUsesFPRet(QualType ResultType);
/// ConstructAttributeList - Get the LLVM attributes and calling convention to
/// use for a particular function type.