Author: ahatanak Date: Wed Mar 28 14:13:14 2018 New Revision: 328731 URL: http://llvm.org/viewvc/llvm-project?rev=328731&view=rev Log: [ObjC++] Make parameter passing and function return compatible with ObjC ObjC and ObjC++ pass non-trivial structs in a way that is incompatible with each other. For example: typedef struct { id f0; __weak id f1; } S; // this code is compiled in c++. extern "C" { void foo(S s); } void caller() { // the caller passes the parameter indirectly and destructs it. foo(S()); } // this function is compiled in c. // 'a' is passed directly and is destructed in the callee. void foo(S a) { } This patch fixes the incompatibility by passing and returning structs with __strong or weak fields using the C ABI in C++ mode. __strong and __weak fields in a struct do not cause the struct to be destructed in the caller and __strong fields do not cause the struct to be passed indirectly. Also, this patch fixes the microsoft ABI bug mentioned here: https://reviews.llvm.org/D41039?id=128767#inline-364710 rdar://problem/38887866 Differential Revision: https://reviews.llvm.org/D44908
Added: cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm - copied, changed from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm Removed: cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/Basic/LangOptions.def cfe/trunk/include/clang/Basic/LangOptions.h cfe/trunk/include/clang/Basic/TargetInfo.h cfe/trunk/include/clang/Frontend/CodeGenOptions.def cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/Basic/TargetInfo.cpp cfe/trunk/lib/Basic/Targets/X86.h cfe/trunk/lib/CodeGen/CGCall.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp cfe/trunk/lib/CodeGen/TargetInfo.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 28 14:13:14 2018 @@ -3559,6 +3559,11 @@ class RecordDecl : public TagDecl { /// pass an object of this class. bool CanPassInRegisters : 1; + /// Indicates whether this struct is destroyed in the callee. This flag is + /// meaningless when Microsoft ABI is used since parameters are always + /// destroyed in the callee. + bool ParamDestroyedInCallee : 1; + protected: RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -3654,6 +3659,14 @@ public: CanPassInRegisters = CanPass; } + bool isParamDestroyedInCallee() const { + return ParamDestroyedInCallee; + } + + void setParamDestroyedInCallee(bool V) { + ParamDestroyedInCallee = V; + } + /// \brief Determines whether this declaration represents the /// injected class name. /// Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Mar 28 14:13:14 2018 @@ -1468,13 +1468,6 @@ public: return data().HasIrrelevantDestructor; } - /// Determine whether the triviality for the purpose of calls for this class - /// is overridden to be trivial because this class or the type of one of its - /// subobjects has attribute "trivial_abi". - bool hasTrivialABIOverride() const { - return canPassInRegisters() && hasNonTrivialDestructor(); - } - /// \brief Determine whether this class has a non-literal or/ volatile type /// non-static data member or base class. bool hasNonLiteralTypeFieldsOrBases() const { Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Wed Mar 28 14:13:14 2018 @@ -808,11 +808,6 @@ public: /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; - /// Determine whether this is a class whose triviality for the purpose of - /// calls is overridden to be trivial because the class or the type of one of - /// its subobjects has attribute "trivial_abi". - bool hasTrivialABIOverride() const; - // Don't promise in the API that anything besides 'const' can be // easily added. Modified: cfe/trunk/include/clang/Basic/LangOptions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.def (original) +++ cfe/trunk/include/clang/Basic/LangOptions.def Wed Mar 28 14:13:14 2018 @@ -284,6 +284,10 @@ LANGOPT(XRayAlwaysEmitCustomEvents, 1, 0 BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") +ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest, + "version of Clang that we should attempt to be ABI-compatible " + "with") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT Modified: cfe/trunk/include/clang/Basic/LangOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.h (original) +++ cfe/trunk/include/clang/Basic/LangOptions.h Wed Mar 28 14:13:14 2018 @@ -102,6 +102,23 @@ public: MSVC2015 = 19 }; + /// Clang versions with different platform ABI conformance. + enum class ClangABI { + /// Attempt to be ABI-compatible with code generated by Clang 3.8.x + /// (SVN r257626). This causes <1 x long long> to be passed in an + /// integer register instead of an SSE register on x64_64. + Ver3_8, + + /// Attempt to be ABI-compatible with code generated by Clang 4.0.x + /// (SVN r291814). This causes move operations to be ignored when + /// determining whether a class type can be passed or returned directly. + Ver4, + + /// Conform to the underlying platform's C and C++ ABIs as closely + /// as we can. + Latest + }; + enum FPContractModeKind { // Form fused FP ops only where result will not be affected. FPC_Off, Modified: cfe/trunk/include/clang/Basic/TargetInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TargetInfo.h (original) +++ cfe/trunk/include/clang/Basic/TargetInfo.h Wed Mar 28 14:13:14 2018 @@ -1053,6 +1053,14 @@ public: } } + enum CallingConvKind { + CCK_Default, + CCK_ClangABI4OrPS4, + CCK_MicrosoftX86_64 + }; + + virtual CallingConvKind getCallingConvKind(bool ClangABICompat4) const; + /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp. virtual bool hasSjLjLowering() const { Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original) +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Wed Mar 28 14:13:14 2018 @@ -138,9 +138,6 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjC CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is ///< enabled. -/// A version of Clang that we should attempt to be ABI-compatible with. -ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest) - VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Wed Mar 28 14:13:14 2018 @@ -2643,9 +2643,11 @@ void ASTContext::adjustExceptionSpec( } bool ASTContext::isParamDestroyedInCallee(QualType T) const { - return getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee() || - T.hasTrivialABIOverride() || - T.isDestructedType() == QualType::DK_nontrivial_c_struct; + if (getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee()) + return true; + if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>()) + return RT->getDecl()->isParamDestroyedInCallee(); + return false; } /// getComplexType - Return the uniqued reference to the type for a complex Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Wed Mar 28 14:13:14 2018 @@ -3951,7 +3951,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind LoadedFieldsFromExternalStorage(false), NonTrivialToPrimitiveDefaultInitialize(false), NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false), - CanPassInRegisters(true) { + CanPassInRegisters(true), ParamDestroyedInCallee(false) { assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Mar 28 14:13:14 2018 @@ -801,7 +801,17 @@ void CXXRecordDecl::addedMember(Decl *D) struct DefinitionData &Data = data(); Data.PlainOldData = false; Data.HasTrivialSpecialMembers = 0; - Data.HasTrivialSpecialMembersForCall = 0; + + // __strong or __weak fields do not make special functions non-trivial + // for the purpose of calls. + Qualifiers::ObjCLifetime LT = T.getQualifiers().getObjCLifetime(); + if (LT != Qualifiers::OCL_Strong && LT != Qualifiers::OCL_Weak) + data().HasTrivialSpecialMembersForCall = 0; + + // Structs with __weak fields should never be passed directly. + if (LT == Qualifiers::OCL_Weak) + setCanPassInRegisters(false); + Data.HasIrrelevantDestructor = false; } else if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Wed Mar 28 14:13:14 2018 @@ -2195,12 +2195,6 @@ bool QualType::isTriviallyCopyableType(c return false; } -bool QualType::hasTrivialABIOverride() const { - if (const auto *RD = getTypePtr()->getAsCXXRecordDecl()) - return RD->hasTrivialABIOverride(); - return false; -} - bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { return !Context.getLangOpts().ObjCAutoRefCount && Context.getLangOpts().ObjCWeak && Modified: cfe/trunk/lib/Basic/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Basic/TargetInfo.cpp (original) +++ cfe/trunk/lib/Basic/TargetInfo.cpp Wed Mar 28 14:13:14 2018 @@ -357,6 +357,14 @@ bool TargetInfo::initFeatureMap( return true; } +TargetInfo::CallingConvKind +TargetInfo::getCallingConvKind(bool ClangABICompat4) const { + if (getCXXABI() != TargetCXXABI::Microsoft && + (ClangABICompat4 || getTriple().getOS() == llvm::Triple::PS4)) + return CCK_ClangABI4OrPS4; + return CCK_Default; +} + LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const { switch (TK) { case OCLTK_Image: Modified: cfe/trunk/lib/Basic/Targets/X86.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.h?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Basic/Targets/X86.h (original) +++ cfe/trunk/lib/Basic/Targets/X86.h Wed Mar 28 14:13:14 2018 @@ -728,6 +728,11 @@ public: Builder.defineMacro("_M_X64", "100"); Builder.defineMacro("_M_AMD64", "100"); } + + TargetInfo::CallingConvKind + getCallingConvKind(bool ClangABICompat4) const override { + return CCK_MicrosoftX86_64; + } }; // x86-64 MinGW target Modified: cfe/trunk/lib/CodeGen/CGCall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Mar 28 14:13:14 2018 @@ -3540,24 +3540,13 @@ void CodeGenFunction::EmitCallArg(CallAr else Slot = CreateAggTemp(type, "agg.tmp"); - bool DestroyedInCallee = true, NeedsEHCleanup = true; - if (const auto *RD = type->getAsCXXRecordDecl()) { - DestroyedInCallee = - RD && RD->hasNonTrivialDestructor() && - (CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default || - RD->hasTrivialABIOverride()); - } else { - NeedsEHCleanup = needsEHCleanup(type.isDestructedType()); - } - - if (DestroyedInCallee) - Slot.setExternallyDestructed(); + Slot.setExternallyDestructed(); EmitAggExpr(E, Slot); RValue RV = Slot.asRValue(); args.add(RV, type); - if (DestroyedInCallee && NeedsEHCleanup) { + if (type->getAsCXXRecordDecl() || needsEHCleanup(type.isDestructedType())) { // Create a no-op GEP between the placeholder and the cleanup so we can // RAUW it successfully. It also serves as a marker of the first // instruction where the cleanup is active. Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Mar 28 14:13:14 2018 @@ -63,13 +63,6 @@ public: bool classifyReturnType(CGFunctionInfo &FI) const override; bool passClassIndirect(const CXXRecordDecl *RD) const { - // Clang <= 4 used the pre-C++11 rule, which ignores move operations. - // The PS4 platform ABI follows the behavior of Clang 3.2. - if (CGM.getCodeGenOpts().getClangABICompat() <= - CodeGenOptions::ClangABI::Ver4 || - CGM.getTriple().getOS() == llvm::Triple::PS4) - return RD->hasNonTrivialDestructorForCall() || - RD->hasNonTrivialCopyConstructorForCall(); return !canCopyArgument(RD); } Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Mar 28 14:13:14 2018 @@ -829,60 +829,7 @@ MicrosoftCXXABI::getRecordArgABI(const C return RAA_Default; case llvm::Triple::x86_64: - bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; - bool DtorIsTrivialForCall = false; - - // If a class has at least one non-deleted, trivial copy constructor, it - // is passed according to the C ABI. Otherwise, it is passed indirectly. - // - // Note: This permits classes with non-trivial copy or move ctors to be - // passed in registers, so long as they *also* have a trivial copy ctor, - // which is non-conforming. - if (RD->needsImplicitCopyConstructor()) { - if (!RD->defaultedCopyConstructorIsDeleted()) { - if (RD->hasTrivialCopyConstructor()) - CopyCtorIsTrivial = true; - if (RD->hasTrivialCopyConstructorForCall()) - CopyCtorIsTrivialForCall = true; - } - } else { - for (const CXXConstructorDecl *CD : RD->ctors()) { - if (CD->isCopyConstructor() && !CD->isDeleted()) { - if (CD->isTrivial()) - CopyCtorIsTrivial = true; - if (CD->isTrivialForCall()) - CopyCtorIsTrivialForCall = true; - } - } - } - - if (RD->needsImplicitDestructor()) { - if (!RD->defaultedDestructorIsDeleted() && - RD->hasTrivialDestructorForCall()) - DtorIsTrivialForCall = true; - } else if (const auto *D = RD->getDestructor()) { - if (!D->isDeleted() && D->isTrivialForCall()) - DtorIsTrivialForCall = true; - } - - // If the copy ctor and dtor are both trivial-for-calls, pass direct. - if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall) - return RAA_Default; - - // If a class has a destructor, we'd really like to pass it indirectly - // because it allows us to elide copies. Unfortunately, MSVC makes that - // impossible for small types, which it will pass in a single register or - // stack slot. Most objects with dtors are large-ish, so handle that early. - // We can't call out all large objects as being indirect because there are - // multiple x64 calling conventions and the C++ ABI code shouldn't dictate - // how we pass large POD types. - - // Note: This permits small classes with nontrivial destructors to be - // passed in registers, which is non-conforming. - if (CopyCtorIsTrivial && - getContext().getTypeSize(RD->getTypeForDecl()) <= 64) - return RAA_Default; - return RAA_Indirect; + return !canCopyArgument(RD) ? RAA_Indirect : RAA_Default; } llvm_unreachable("invalid enum"); Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Mar 28 14:13:14 2018 @@ -2131,8 +2131,8 @@ class X86_64ABIInfo : public SwiftABIInf /// classify it as INTEGER (for compatibility with older clang compilers). bool classifyIntegerMMXAsSSE() const { // Clang <= 3.8 did not do this. - if (getCodeGenOpts().getClangABICompat() <= - CodeGenOptions::ClangABI::Ver3_8) + if (getContext().getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver3_8) return false; const llvm::Triple &Triple = getTarget().getTriple(); Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Wed Mar 28 14:13:14 2018 @@ -633,33 +633,6 @@ static bool ParseCodeGenArgs(CodeGenOpti if (!Opts.ProfileInstrumentUsePath.empty()) setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); - if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { - Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest); - - StringRef Ver = A->getValue(); - std::pair<StringRef, StringRef> VerParts = Ver.split('.'); - unsigned Major, Minor = 0; - - // Check the version number is valid: either 3.x (0 <= x <= 9) or - // y or y.0 (4 <= y <= current version). - if (!VerParts.first.startswith("0") && - !VerParts.first.getAsInteger(10, Major) && - 3 <= Major && Major <= CLANG_VERSION_MAJOR && - (Major == 3 ? VerParts.second.size() == 1 && - !VerParts.second.getAsInteger(10, Minor) - : VerParts.first.size() == Ver.size() || - VerParts.second == "0")) { - // Got a valid version number. - if (Major == 3 && Minor <= 8) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8); - else if (Major <= 4) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4); - } else if (Ver != "latest") { - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); - } - } - Opts.CoverageMapping = Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); @@ -2670,6 +2643,33 @@ static void ParseLangArgs(LangOptions &O // -fallow-editor-placeholders Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); + + if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { + Opts.setClangABICompat(LangOptions::ClangABI::Latest); + + StringRef Ver = A->getValue(); + std::pair<StringRef, StringRef> VerParts = Ver.split('.'); + unsigned Major, Minor = 0; + + // Check the version number is valid: either 3.x (0 <= x <= 9) or + // y or y.0 (4 <= y <= current version). + if (!VerParts.first.startswith("0") && + !VerParts.first.getAsInteger(10, Major) && + 3 <= Major && Major <= CLANG_VERSION_MAJOR && + (Major == 3 ? VerParts.second.size() == 1 && + !VerParts.second.getAsInteger(10, Minor) + : VerParts.first.size() == Ver.size() || + VerParts.second == "0")) { + // Got a valid version number. + if (Major == 3 && Minor <= 8) + Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8); + else if (Major <= 4) + Opts.setClangABICompat(LangOptions::ClangABI::Ver4); + } else if (Ver != "latest") { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + } } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 28 14:13:14 2018 @@ -15461,8 +15461,10 @@ void Sema::ActOnFields(Scope *S, SourceL QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy(); if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) Record->setNonTrivialToPrimitiveCopy(true); - if (FT.isDestructedType()) + if (FT.isDestructedType()) { Record->setNonTrivialToPrimitiveDestroy(true); + Record->setParamDestroyedInCallee(true); + } if (!FT.canPassInRegisters()) Record->setCanPassInRegisters(false); } Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 28 14:13:14 2018 @@ -5791,12 +5791,21 @@ static void DefineImplicitSpecialMember( } } -/// Determine whether a type is permitted to be passed or returned in -/// registers, per C++ [class.temporary]p3. -static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { +/// Determine whether a type would be destructed in the callee if it had a +/// non-trivial destructor. The rules here are based on C++ [class.temporary]p3, +/// which determines whether a struct can be passed to or returned from +/// functions in registers. +static bool paramCanBeDestroyedInCallee(Sema &S, CXXRecordDecl *D, + TargetInfo::CallingConvKind CCK) { if (D->isDependentType() || D->isInvalidDecl()) return false; + // Clang <= 4 used the pre-C++11 rule, which ignores move operations. + // The PS4 platform ABI follows the behavior of Clang 3.2. + if (CCK == TargetInfo::CCK_ClangABI4OrPS4) + return !D->hasNonTrivialDestructorForCall() && + !D->hasNonTrivialCopyConstructorForCall(); + // Per C++ [class.temporary]p3, the relevant condition is: // each copy constructor, move constructor, and destructor of X is // either trivial or deleted, and X has at least one non-deleted copy @@ -5838,6 +5847,77 @@ static bool computeCanPassInRegisters(Se return HasNonDeletedCopyOrMove; } +static bool computeCanPassInRegister(bool DestroyedInCallee, + const CXXRecordDecl *RD, + TargetInfo::CallingConvKind CCK, + Sema &S) { + if (RD->isDependentType() || RD->isInvalidDecl()) + return true; + + // The param cannot be passed in registers if CanPassInRegisters is already + // set to false. + if (!RD->canPassInRegisters()) + return false; + + if (CCK != TargetInfo::CCK_MicrosoftX86_64) + return DestroyedInCallee; + + bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; + bool DtorIsTrivialForCall = false; + + // If a class has at least one non-deleted, trivial copy constructor, it + // is passed according to the C ABI. Otherwise, it is passed indirectly. + // + // Note: This permits classes with non-trivial copy or move ctors to be + // passed in registers, so long as they *also* have a trivial copy ctor, + // which is non-conforming. + if (RD->needsImplicitCopyConstructor()) { + if (!RD->defaultedCopyConstructorIsDeleted()) { + if (RD->hasTrivialCopyConstructor()) + CopyCtorIsTrivial = true; + if (RD->hasTrivialCopyConstructorForCall()) + CopyCtorIsTrivialForCall = true; + } + } else { + for (const CXXConstructorDecl *CD : RD->ctors()) { + if (CD->isCopyConstructor() && !CD->isDeleted()) { + if (CD->isTrivial()) + CopyCtorIsTrivial = true; + if (CD->isTrivialForCall()) + CopyCtorIsTrivialForCall = true; + } + } + } + + if (RD->needsImplicitDestructor()) { + if (!RD->defaultedDestructorIsDeleted() && + RD->hasTrivialDestructorForCall()) + DtorIsTrivialForCall = true; + } else if (const auto *D = RD->getDestructor()) { + if (!D->isDeleted() && D->isTrivialForCall()) + DtorIsTrivialForCall = true; + } + + // If the copy ctor and dtor are both trivial-for-calls, pass direct. + if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall) + return true; + + // If a class has a destructor, we'd really like to pass it indirectly + // because it allows us to elide copies. Unfortunately, MSVC makes that + // impossible for small types, which it will pass in a single register or + // stack slot. Most objects with dtors are large-ish, so handle that early. + // We can't call out all large objects as being indirect because there are + // multiple x64 calling conventions and the C++ ABI code shouldn't dictate + // how we pass large POD types. + + // Note: This permits small classes with nontrivial destructors to be + // passed in registers, which is non-conforming. + if (CopyCtorIsTrivial && + S.getASTContext().getTypeSize(RD->getTypeForDecl()) <= 64) + return true; + return false; +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -6001,7 +6081,17 @@ void Sema::CheckCompletedCXXClass(CXXRec checkClassLevelDLLAttribute(Record); - Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record)); + bool ClangABICompat4 = + Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4; + TargetInfo::CallingConvKind CCK = + Context.getTargetInfo().getCallingConvKind(ClangABICompat4); + bool DestroyedInCallee = paramCanBeDestroyedInCallee(*this, Record, CCK); + + if (Record->hasNonTrivialDestructor()) + Record->setParamDestroyedInCallee(DestroyedInCallee); + + Record->setCanPassInRegisters( + computeCanPassInRegister(DestroyedInCallee, Record, CCK, *this)); } /// Look up the special member function that would be called by a special Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Mar 28 14:13:14 2018 @@ -743,6 +743,7 @@ ASTDeclReader::VisitRecordDeclImpl(Recor RD->setNonTrivialToPrimitiveCopy(Record.readInt()); RD->setNonTrivialToPrimitiveDestroy(Record.readInt()); RD->setCanPassInRegisters(Record.readInt()); + RD->setParamDestroyedInCallee(Record.readInt()); return Redecl; } @@ -4109,6 +4110,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, OldDD && (OldDD->Definition != RD || !Reader.PendingFakeDefinitionData.count(OldDD)); RD->setCanPassInRegisters(Record.readInt()); + RD->setParamDestroyedInCallee(Record.readInt()); ReadCXXRecordDefinition(RD, /*Update*/true); // Visible update is handled separately. Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Mar 28 14:13:14 2018 @@ -5194,6 +5194,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(R auto *RD = cast<CXXRecordDecl>(D); UpdatedDeclContexts.insert(RD->getPrimaryContext()); Record.push_back(RD->canPassInRegisters()); + Record.push_back(RD->isParamDestroyedInCallee()); Record.AddCXXDefinitionData(RD); Record.AddOffset(WriteDeclContextLexicalBlock( *Context, const_cast<CXXRecordDecl *>(RD))); Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Mar 28 14:13:14 2018 @@ -470,6 +470,7 @@ void ASTDeclWriter::VisitRecordDecl(Reco Record.push_back(D->isNonTrivialToPrimitiveCopy()); Record.push_back(D->isNonTrivialToPrimitiveDestroy()); Record.push_back(D->canPassInRegisters()); + Record.push_back(D->isParamDestroyedInCallee()); if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() && @@ -1912,6 +1913,8 @@ void ASTWriter::WriteDeclAbbrevs() { // isNonTrivialToPrimitiveDestroy Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // canPassInRegisters + // isParamDestroyedInCallee + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // DC Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (original) +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp Wed Mar 28 14:13:14 2018 @@ -172,12 +172,9 @@ void small_arg_with_dtor(SmallWithDtor s void call_small_arg_with_dtor() { small_arg_with_dtor(SmallWithDtor()); } -// The temporary is copied, so it's destroyed in the caller as well as the -// callee. // WIN64-LABEL: define dso_local void @"?call_small_arg_with_dtor@@YAXXZ"() // WIN64: call %struct.SmallWithDtor* @"??0SmallWithDtor@@QEAA@XZ" // WIN64: call void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %{{.*}}) -// WIN64: call void @"??1SmallWithDtor@@QEAA@XZ" // WIN64: ret void // Test that references aren't destroyed in the callee. Modified: cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm (original) +++ cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm Wed Mar 28 14:13:14 2018 @@ -31,6 +31,8 @@ void test_ObjCMember_copy_construct_dest void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) { // CHECK: {{call.*_ZN10ObjCMemberaSERKS_}} m1 = m2; + // CHECK-NEXT: call void @_ZN10ObjCMemberD1Ev( + // CHECK-NEXT: call void @_ZN10ObjCMemberD1Ev( // CHECK-NEXT: ret void } @@ -58,6 +60,8 @@ void test_ObjCArrayMember_copy_construct void test_ObjCArrayMember_copy_assign(ObjCArrayMember m1, ObjCArrayMember m2) { // CHECK: {{call.*@_ZN15ObjCArrayMemberaSERKS_}} m1 = m2; + // CHECK-NEXT: call void @_ZN15ObjCArrayMemberD1Ev( + // CHECK-NEXT: call void @_ZN15ObjCArrayMemberD1Ev( // CHECK-NEXT: ret void } @@ -79,7 +83,8 @@ void test_ObjCBlockMember_default_constr void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) { // CHECK: call void @_ZN15ObjCBlockMemberC1ERKS_ ObjCBlockMember m2 = m1; - // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev + // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev( + // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev( // CHECK-NEXT: ret void } @@ -87,6 +92,8 @@ void test_ObjCBlockMember_copy_construct void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) { // CHECK: {{call.*_ZN15ObjCBlockMemberaSERKS_}} m1 = m2; + // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev( + // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev( // CHECK-NEXT: ret void } Copied: cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm (from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm) URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm?p2=cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm&p1=cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm&r1=328730&r2=328731&rev=328731&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (original) +++ cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm Wed Mar 28 14:13:14 2018 @@ -1,27 +1,60 @@ // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s + +// Check that structs consisting solely of __strong or __weak pointer fields are +// destructed in the callee function and structs consisting solely of __strong +// pointer fields are passed directly. // CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* } // CHECK: %[[STRUCT_STRONG:.*]] = type { i8* } // CHECK: %[[STRUCT_S:.*]] = type { i8* } +// CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* } +#ifdef TRIVIALABI struct __attribute__((trivial_abi)) StrongWeak { +#else +struct StrongWeak { +#endif id fstrong; __weak id fweak; }; +#ifdef TRIVIALABI struct __attribute__((trivial_abi)) Strong { +#else +struct Strong { +#endif id fstrong; }; template<class T> +#ifdef TRIVIALABI struct __attribute__((trivial_abi)) S { +#else +struct S { +#endif T a; }; +struct NonTrivial { + NonTrivial(); + NonTrivial(const NonTrivial &); + ~NonTrivial(); + int *a; +}; + +// This struct is not passed directly nor destructed in the callee because f0 +// has type NonTrivial. +struct ContainsNonTrivial { + NonTrivial f0; + id f1; +}; + // CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}}) -// CHECK-NOT: call -// CHECK: ret void +// CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev( +// CHECK-NEXT: ret void void testParamStrongWeak(StrongWeak a) { } @@ -33,7 +66,7 @@ void testParamStrongWeak(StrongWeak a) { // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]]) // CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]]) -// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]]) +// CHECK-NOT: call // CHECK: ret void void testCallStrongWeak(StrongWeak *a) { @@ -96,8 +129,23 @@ Strong testReturnStrong(Strong *a) { } // CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}}) +// CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev( +// CHECK-NEXT: ret void + +void testParamWeakTemplate(S<__weak id> a) { +} + +// CHECK: define void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) // CHECK-NOT: call // CHECK: ret void -void testParamWeakTemplate(S<__weak id> a) { +void testParamContainsNonTrivial(ContainsNonTrivial a) { +} + +// CHECK: define void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial( +// CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) +// CHECK: call %struct.ContainsNonTrivial* @_ZN18ContainsNonTrivialD1Ev(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) + +void testCallContainsNonTrivial(ContainsNonTrivial *a) { + testParamContainsNonTrivial(*a); } Modified: cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm?rev=328731&r1=328730&r2=328731&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm (original) +++ cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm Wed Mar 28 14:13:14 2018 @@ -1,11 +1,13 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++1z -fobjc-arc -o - %s | FileCheck %s struct S0 { + ~S0(); id f; }; struct S1 { S1(); + ~S1(); S1(S0); id f; }; Removed: cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm?rev=328730&view=auto ============================================================================== --- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (original) +++ cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (removed) @@ -1,103 +0,0 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s - -// CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* } -// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* } -// CHECK: %[[STRUCT_S:.*]] = type { i8* } - -struct __attribute__((trivial_abi)) StrongWeak { - id fstrong; - __weak id fweak; -}; - -struct __attribute__((trivial_abi)) Strong { - id fstrong; -}; - -template<class T> -struct __attribute__((trivial_abi)) S { - T a; -}; - -// CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}}) -// CHECK-NOT: call -// CHECK: ret void - -void testParamStrongWeak(StrongWeak a) { -} - -// CHECK: define void @_Z18testCallStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[A:.*]]) -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 -// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8 -// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]]) -// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]]) -// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]]) -// CHECK: ret void - -void testCallStrongWeak(StrongWeak *a) { - testParamStrongWeak(*a); -} - -// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 -// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_RESULT]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]]) -// CHECK: ret void - -StrongWeak testReturnStrongWeak(StrongWeak *a) { - return *a; -} - -// CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]]) -// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8 -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0 -// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i8* -// CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8 -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* %[[A]]) -// CHECK: ret void - -// CHECK: define linkonce_odr %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev( - -void testParamStrong(Strong a) { -} - -// CHECK: define void @_Z14testCallStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]]) -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8 -// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8 -// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[AGG_TMP]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]]) -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0 -// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8 -// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64 -// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]]) -// CHECK: ret void - -void testCallStrong(Strong *a) { - testParamStrong(*a); -} - -// CHECK: define i64 @_Z16testReturnStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]]) -// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8 -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8 -// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[RETVAL]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]]) -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0 -// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8 -// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64 -// CHECK: ret i64 %[[COERCE_VAL_PI]] - -Strong testReturnStrong(Strong *a) { - return *a; -} - -// CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}}) -// CHECK-NOT: call -// CHECK: ret void - -void testParamWeakTemplate(S<__weak id> a) { -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits