From: John McCall Date: Tue, 1 Mar 2016 22:18:03 +0000 (+0000) Subject: Mangle extended qualifiers in the proper order and mangle the X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=07daf721fbdc337db3c2cd5dc303b543ecf9a477;p=platform%2Fupstream%2Fllvm.git Mangle extended qualifiers in the proper order and mangle the ARC ownership-convention function type modifications. According to the Itanium ABI, vendor extended qualifiers are supposed to be mangled in reverse-alphabetical order before any CVR qualifiers. The ARC function type conventions are plausibly order-significant (they are associated with the function type), which permits us to ignore the need to correctly inter-order them with any other vendor qualifiers on the parameter and return types. Implementing these rules correctly is technically an ABI break. Apple is comfortable with the risk of incompatibility here for the ARC features, and I believe that address-space qualification is still uncommon enough to allow us to adopt the conforming rule without serious risk. Still, targets which make heavy use of address space qualification may want to revert to the non-conforming order. llvm-svn: 262414 --- diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index d30f95d..68f76f5 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -364,6 +364,7 @@ private: StringRef Prefix = ""); void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleVendorQualifier(StringRef qualifier); void mangleQualifiers(Qualifiers Quals); void mangleRefQualifier(RefQualifierKind RefQualifier); @@ -377,7 +378,10 @@ private: void mangleType(const TagType*); void mangleType(TemplateName); - void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType, + static StringRef getCallingConvQualifierName(CallingConv CC); + void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info); + void mangleExtFunctionInfo(const FunctionType *T); + void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType, const FunctionDecl *FD = nullptr); void mangleNeonVectorType(const VectorType *T); void mangleAArch64NeonVectorType(const VectorType *T); @@ -523,7 +527,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { FD = PrimaryTemplate->getTemplatedDecl(); } - mangleBareFunctionType(FD->getType()->getAs(), + mangleBareFunctionType(FD->getType()->castAs(), MangleReturnType, FD); } @@ -1767,14 +1771,9 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { } void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { - // ::= [r] [V] [K] # restrict (C99), volatile, const - if (Quals.hasRestrict()) - Out << 'r'; - if (Quals.hasVolatile()) - Out << 'V'; - if (Quals.hasConst()) - Out << 'K'; + // Vendor qualifiers come first. + // Address space qualifiers start with an ordinary letter. if (Quals.hasAddressSpace()) { // Address space extension: // @@ -1802,10 +1801,10 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { case LangAS::cuda_shared: ASString = "CUshared"; break; } } - Out << 'U' << ASString.size() << ASString; + mangleVendorQualifier(ASString); } - - StringRef LifetimeName; + + // The ARC ownership qualifiers start with underscores. switch (Quals.getObjCLifetime()) { // Objective-C ARC Extension: // @@ -1816,15 +1815,15 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { break; case Qualifiers::OCL_Weak: - LifetimeName = "__weak"; + mangleVendorQualifier("__weak"); break; case Qualifiers::OCL_Strong: - LifetimeName = "__strong"; + mangleVendorQualifier("__strong"); break; case Qualifiers::OCL_Autoreleasing: - LifetimeName = "__autoreleasing"; + mangleVendorQualifier("__autoreleasing"); break; case Qualifiers::OCL_ExplicitNone: @@ -1837,8 +1836,18 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // in any type signatures that need to be mangled. break; } - if (!LifetimeName.empty()) - Out << 'U' << LifetimeName.size() << LifetimeName; + + // ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals.hasRestrict()) + Out << 'r'; + if (Quals.hasVolatile()) + Out << 'V'; + if (Quals.hasConst()) + Out << 'K'; +} + +void CXXNameMangler::mangleVendorQualifier(StringRef name) { + Out << 'U' << name.size() << name; } void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { @@ -2137,10 +2146,63 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { } } +StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { + switch (CC) { + case CC_C: + return ""; + + case CC_X86StdCall: + case CC_X86FastCall: + case CC_X86ThisCall: + case CC_X86VectorCall: + case CC_X86Pascal: + case CC_X86_64Win64: + case CC_X86_64SysV: + case CC_AAPCS: + case CC_AAPCS_VFP: + case CC_IntelOclBicc: + case CC_SpirFunction: + case CC_SpirKernel: + // FIXME: we should be mangling all of the above. + return ""; + } + llvm_unreachable("bad calling convention"); +} + +void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) { + // Fast path. + if (T->getExtInfo() == FunctionType::ExtInfo()) + return; + + // Vendor-specific qualifiers are emitted in reverse alphabetical order. + // This will get more complicated in the future if we mangle other + // things here; but for now, since we mangle ns_returns_retained as + // a qualifier on the result type, we can get away with this: + StringRef CCQualifier = getCallingConvQualifierName(T->getExtInfo().getCC()); + if (!CCQualifier.empty()) + mangleVendorQualifier(CCQualifier); + + // FIXME: regparm + // FIXME: noreturn +} + +void +CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) { + // Vendor-specific qualifiers are emitted in reverse alphabetical order. + + // Note that these are *not* substitution candidates. Demanglers might + // have trouble with this if the parameter type is fully substituted. + + if (PI.isConsumed()) + Out << "U11ns_consumed"; +} + // ::= // ::= [] F [Y] // [] E void CXXNameMangler::mangleType(const FunctionProtoType *T) { + mangleExtFunctionInfo(T); + // Mangle CV-qualifiers, if present. These are 'this' qualifiers, // e.g. "const" in "int (A::*)() const". mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals())); @@ -2173,12 +2235,9 @@ void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { Out << 'E'; } -void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, +void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto, bool MangleReturnType, const FunctionDecl *FD) { - // We should never be mangling something without a prototype. - const FunctionProtoType *Proto = cast(T); - // Record that we're in a function type. See mangleFunctionParam // for details on what we're trying to achieve here. FunctionTypeDepthState saved = FunctionTypeDepth.push(); @@ -2186,7 +2245,20 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, // ::= + if (MangleReturnType) { FunctionTypeDepth.enterResultType(); - mangleType(Proto->getReturnType()); + + // Mangle ns_returns_retained as an order-sensitive qualifier here. + if (Proto->getExtInfo().getProducesResult()) + mangleVendorQualifier("ns_returns_retained"); + + // Mangle the return type without any direct ARC ownership qualifiers. + QualType ReturnTy = Proto->getReturnType(); + if (ReturnTy.getObjCLifetime()) { + auto SplitReturnTy = ReturnTy.split(); + SplitReturnTy.Quals.removeObjCLifetime(); + ReturnTy = getASTContext().getQualifiedType(SplitReturnTy); + } + mangleType(ReturnTy); + FunctionTypeDepth.leaveResultType(); } @@ -2200,7 +2272,13 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, assert(!FD || FD->getNumParams() == Proto->getNumParams()); for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { - const auto &ParamTy = Proto->getParamType(I); + // Mangle extended parameter info as order-sensitive qualifiers here. + if (Proto->hasExtParameterInfos()) { + mangleExtParameterInfo(Proto->getExtParameterInfo(I)); + } + + // Mangle the type. + QualType ParamTy = Proto->getParamType(I); mangleType(Context.getASTContext().getSignatureParameterType(ParamTy)); if (FD) { diff --git a/clang/test/CodeGenCXX/mangle-address-space.cpp b/clang/test/CodeGenCXX/mangle-address-space.cpp index f18480d..cd10384 100644 --- a/clang/test/CodeGenCXX/mangle-address-space.cpp +++ b/clang/test/CodeGenCXX/mangle-address-space.cpp @@ -10,3 +10,6 @@ typedef OpaqueType __attribute__((address_space(100))) * OpaqueTypePtr; // CHECK-LABEL: define {{.*}}void @_Z2f0PU5AS10010OpaqueType void f0(OpaqueTypePtr) { } + +// CHECK-LABEL: define {{.*}}void @_Z2f1PU3AS1Kc +void f1(char __attribute__((address_space(1))) const *p) {} \ No newline at end of file diff --git a/clang/test/CodeGenObjCXX/arc-attrs.mm b/clang/test/CodeGenObjCXX/arc-attrs.mm index 0f0610f..d571677 100644 --- a/clang/test/CodeGenObjCXX/arc-attrs.mm +++ b/clang/test/CodeGenObjCXX/arc-attrs.mm @@ -12,7 +12,7 @@ void sanityTest() { id x = makeObject1(); // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z11makeObject2v() - // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]]) + // CHECK-NEXT: call void @_Z13releaseObjectU11ns_consumedP11objc_object(i8* [[OBJ2]]) releaseObject(makeObject2()); // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) @@ -31,16 +31,16 @@ void releaseObjectT(__attribute__((ns_consumed)) T); // CHECK-LABEL: define void @_Z12templateTestv void templateTest() { // CHECK: [[X:%.*]] = alloca i8*, align 8 - // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectET_v() + // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectEU19ns_returns_retainedT_v() // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8 id x = makeObjectT1(); - // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z12makeObjectT2IU8__strongP11objc_objectET_v() - // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]]) + // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z12makeObjectT2IU8__strongP11objc_objectEU19ns_returns_retainedT_v() + // CHECK-NEXT: call void @_Z13releaseObjectU11ns_consumedP11objc_object(i8* [[OBJ2]]) releaseObject(makeObjectT2()); // CHECK-NEXT: [[OBJ3:%.*]] = call i8* @_Z11makeObject1v() - // CHECK-NEXT: call void @_Z14releaseObjectTIU8__strongP11objc_objectEvT_(i8* [[OBJ3]]) + // CHECK-NEXT: call void @_Z14releaseObjectTIU8__strongP11objc_objectEvU11ns_consumedT_(i8* [[OBJ3]]) releaseObjectT(makeObject1()); // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) diff --git a/clang/test/CodeGenObjCXX/arc-mangle.mm b/clang/test/CodeGenObjCXX/arc-mangle.mm index a168d41..84acbdb 100644 --- a/clang/test/CodeGenObjCXX/arc-mangle.mm +++ b/clang/test/CodeGenObjCXX/arc-mangle.mm @@ -8,15 +8,20 @@ void f(__weak id *) {} void f(__autoreleasing id *) {} // CHECK-LABEL: define {{.*}}void @_Z1fPP11objc_object(i8**) void f(__unsafe_unretained id *) {} -// CHECK-LABEL: define {{.*}}void @_Z1fPKU8__strongP11objc_object(i8**) +// CHECK-LABEL: define {{.*}}void @_Z1fPU8__strongKP11objc_object(i8**) void f(const __strong id *) {} -// CHECK-LABEL: define {{.*}}void @_Z1fPKU6__weakP11objc_object(i8**) +// CHECK-LABEL: define {{.*}}void @_Z1fPU6__weakKP11objc_object(i8**) void f(const __weak id *) {} -// CHECK-LABEL: define {{.*}}void @_Z1fPKU15__autoreleasingP11objc_object(i8**) +// CHECK-LABEL: define {{.*}}void @_Z1fPU15__autoreleasingKP11objc_object(i8**) void f(const __autoreleasing id *) {} // CHECK-LABEL: define {{.*}}void @_Z1fPKP11objc_object(i8**) void f(const __unsafe_unretained id *) {} - +// CHECK-LABEL: define {{.*}}void @_Z1fPFU19ns_returns_retainedP11objc_objectvE +void f(__attribute__((ns_returns_retained)) id (*fn)()) {} +// CHECK-LABEL: define {{.*}}void @_Z1fPFP11objc_objectU11ns_consumedS0_S0_E +void f(id (*fn)(__attribute__((ns_consumed)) id, id)) {} +// CHECK-LABEL: define {{.*}}void @_Z1fPFP11objc_objectS0_U11ns_consumedS0_E +void f(__strong id (*fn)(id, __attribute__((ns_consumed)) id)) {} template struct unsigned_c { }; diff --git a/clang/test/CodeGenObjCXX/arc-move.mm b/clang/test/CodeGenObjCXX/arc-move.mm index 76fb15b..d1710e2 100644 --- a/clang/test/CodeGenObjCXX/arc-move.mm +++ b/clang/test/CodeGenObjCXX/arc-move.mm @@ -72,10 +72,10 @@ void library_move(__strong id &y) { // CHECK-NEXT: ret void } -// CHECK-LABEL: define void @_Z10const_moveRKU8__strongP11objc_object( +// CHECK-LABEL: define void @_Z10const_moveRU8__strongKP11objc_object( void const_move(const __strong id &x) { // CHECK: [[Y:%.*]] = alloca i8*, - // CHECK: [[X:%.*]] = call dereferenceable({{[0-9]+}}) i8** @_Z4moveIRKU8__strongP11objc_objectEON16remove_referenceIT_E4typeEOS5_( + // CHECK: [[X:%.*]] = call dereferenceable({{[0-9]+}}) i8** @_Z4moveIRU8__strongKP11objc_objectEON16remove_referenceIT_E4typeEOS5_( // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) // CHECK-NEXT: store i8* [[T1]], i8** [[Y]]