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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@262414 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2016-03-01 22:18:03 +00:00
parent edfad5e176
commit a1ba3c7ed2
5 changed files with 120 additions and 34 deletions

View File

@ -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<FunctionType>(),
mangleBareFunctionType(FD->getType()->castAs<FunctionProtoType>(),
MangleReturnType, FD);
}
@ -1767,14 +1771,9 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
}
void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// <CV-qualifiers> ::= [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;
// <CV-qualifiers> ::= [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";
}
// <type> ::= <function-type>
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] 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<FunctionProtoType>(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,
// <bare-function-type> ::= <signature type>+
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) {

View File

@ -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) {}

View File

@ -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<id>();
// 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<id>());
// 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)

View File

@ -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<unsigned N> struct unsigned_c { };

View File

@ -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]]