summaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp199
1 files changed, 175 insertions, 24 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index df33fc3e8200..85bd53741e18 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -395,6 +395,7 @@ void CodeGenModule::Release() {
applyGlobalValReplacements();
applyReplacements();
checkAliases();
+ emitMultiVersionFunctions();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
EmitCXXThreadLocalInitFunc();
@@ -725,36 +726,48 @@ void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const {
GV->setThreadLocalMode(TLM);
}
-StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
- GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+static void AppendTargetMangling(const CodeGenModule &CGM,
+ const TargetAttr *Attr, raw_ostream &Out) {
+ if (Attr->isDefaultVersion())
+ return;
- // Some ABIs don't have constructor variants. Make sure that base and
- // complete constructors get mangled the same.
- if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
- if (!getTarget().getCXXABI().hasConstructorVariants()) {
- CXXCtorType OrigCtorType = GD.getCtorType();
- assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
- if (OrigCtorType == Ctor_Base)
- CanonicalGD = GlobalDecl(CD, Ctor_Complete);
- }
+ Out << '.';
+ const auto &Target = CGM.getTarget();
+ TargetAttr::ParsedTargetAttr Info =
+ Attr->parse([&Target](StringRef LHS, StringRef RHS) {
+ return Target.multiVersionSortPriority(LHS) >
+ Target.multiVersionSortPriority(RHS);
+ });
+
+ bool IsFirst = true;
+
+ if (!Info.Architecture.empty()) {
+ IsFirst = false;
+ Out << "arch_" << Info.Architecture;
}
- auto FoundName = MangledDeclNames.find(CanonicalGD);
- if (FoundName != MangledDeclNames.end())
- return FoundName->second;
+ for (StringRef Feat : Info.Features) {
+ if (!IsFirst)
+ Out << '_';
+ IsFirst = false;
+ Out << Feat.substr(1);
+ }
+}
- const auto *ND = cast<NamedDecl>(GD.getDecl());
+static std::string getMangledNameImpl(const CodeGenModule &CGM, GlobalDecl GD,
+ const NamedDecl *ND,
+ bool OmitTargetMangling = false) {
SmallString<256> Buffer;
- StringRef Str;
- if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) {
+ llvm::raw_svector_ostream Out(Buffer);
+ MangleContext &MC = CGM.getCXXABI().getMangleContext();
+ if (MC.shouldMangleDeclName(ND)) {
llvm::raw_svector_ostream Out(Buffer);
if (const auto *D = dyn_cast<CXXConstructorDecl>(ND))
- getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
+ MC.mangleCXXCtor(D, GD.getCtorType(), Out);
else if (const auto *D = dyn_cast<CXXDestructorDecl>(ND))
- getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
+ MC.mangleCXXDtor(D, GD.getDtorType(), Out);
else
- getCXXABI().getMangleContext().mangleName(ND, Out);
- Str = Out.str();
+ MC.mangleName(ND, Out);
} else {
IdentifierInfo *II = ND->getIdentifier();
assert(II && "Attempt to mangle unnamed decl.");
@@ -764,14 +777,74 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
FD->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) {
llvm::raw_svector_ostream Out(Buffer);
Out << "__regcall3__" << II->getName();
- Str = Out.str();
} else {
- Str = II->getName();
+ Out << II->getName();
+ }
+ }
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND))
+ if (FD->isMultiVersion() && !OmitTargetMangling)
+ AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
+ return Out.str();
+}
+
+void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD,
+ const FunctionDecl *FD) {
+ if (!FD->isMultiVersion())
+ return;
+
+ // Get the name of what this would be without the 'target' attribute. This
+ // allows us to lookup the version that was emitted when this wasn't a
+ // multiversion function.
+ std::string NonTargetName =
+ getMangledNameImpl(*this, GD, FD, /*OmitTargetMangling=*/true);
+ GlobalDecl OtherGD;
+ if (lookupRepresentativeDecl(NonTargetName, OtherGD)) {
+ assert(OtherGD.getCanonicalDecl()
+ .getDecl()
+ ->getAsFunction()
+ ->isMultiVersion() &&
+ "Other GD should now be a multiversioned function");
+ // OtherFD is the version of this function that was mangled BEFORE
+ // becoming a MultiVersion function. It potentially needs to be updated.
+ const FunctionDecl *OtherFD =
+ OtherGD.getCanonicalDecl().getDecl()->getAsFunction();
+ std::string OtherName = getMangledNameImpl(*this, OtherGD, OtherFD);
+ // This is so that if the initial version was already the 'default'
+ // version, we don't try to update it.
+ if (OtherName != NonTargetName) {
+ Manglings.erase(NonTargetName);
+ auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD));
+ MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first();
+ if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName))
+ Entry->setName(OtherName);
}
}
+}
+
+StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
+ GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+
+ // Some ABIs don't have constructor variants. Make sure that base and
+ // complete constructors get mangled the same.
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
+ if (!getTarget().getCXXABI().hasConstructorVariants()) {
+ CXXCtorType OrigCtorType = GD.getCtorType();
+ assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
+ if (OrigCtorType == Ctor_Base)
+ CanonicalGD = GlobalDecl(CD, Ctor_Complete);
+ }
+ }
+
+ auto FoundName = MangledDeclNames.find(CanonicalGD);
+ if (FoundName != MangledDeclNames.end())
+ return FoundName->second;
+
// Keep the first result in the case of a mangling collision.
- auto Result = Manglings.insert(std::make_pair(Str, GD));
+ const auto *ND = cast<NamedDecl>(GD.getDecl());
+ auto Result =
+ Manglings.insert(std::make_pair(getMangledNameImpl(*this, GD, ND), GD));
return MangledDeclNames[CanonicalGD] = Result.first->first();
}
@@ -2061,6 +2134,74 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *NewFn);
+void CodeGenModule::emitMultiVersionFunctions() {
+ for (GlobalDecl GD : MultiVersionFuncs) {
+ SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+ getContext().forEachMultiversionedFunctionVersion(
+ FD, [this, &GD, &Options](const FunctionDecl *CurFD) {
+ GlobalDecl CurGD{
+ (CurFD->isDefined() ? CurFD->getDefinition() : CurFD)};
+ StringRef MangledName = getMangledName(CurGD);
+ llvm::Constant *Func = GetGlobalValue(MangledName);
+ if (!Func) {
+ if (CurFD->isDefined()) {
+ EmitGlobalFunctionDefinition(CurGD, nullptr);
+ Func = GetGlobalValue(MangledName);
+ } else {
+ const CGFunctionInfo &FI =
+ getTypes().arrangeGlobalDeclaration(GD);
+ llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
+ Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
+ /*DontDefer=*/false, ForDefinition);
+ }
+ assert(Func && "This should have just been created");
+ }
+ Options.emplace_back(getTarget(), cast<llvm::Function>(Func),
+ CurFD->getAttr<TargetAttr>()->parse());
+ });
+
+ llvm::Function *ResolverFunc = cast<llvm::Function>(
+ GetGlobalValue((getMangledName(GD) + ".resolver").str()));
+ std::stable_sort(
+ Options.begin(), Options.end(),
+ std::greater<CodeGenFunction::MultiVersionResolverOption>());
+ CodeGenFunction CGF(*this);
+ CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+ }
+}
+
+/// If an ifunc for the specified mangled name is not in the module, create and
+/// return an llvm IFunc Function with the specified type.
+llvm::Constant *
+CodeGenModule::GetOrCreateMultiVersionIFunc(GlobalDecl GD, llvm::Type *DeclTy,
+ StringRef MangledName,
+ const FunctionDecl *FD) {
+ std::string IFuncName = (MangledName + ".ifunc").str();
+ if (llvm::GlobalValue *IFuncGV = GetGlobalValue(IFuncName))
+ return IFuncGV;
+
+ // Since this is the first time we've created this IFunc, make sure
+ // that we put this multiversioned function into the list to be
+ // replaced later.
+ MultiVersionFuncs.push_back(GD);
+
+ std::string ResolverName = (MangledName + ".resolver").str();
+ llvm::Type *ResolverType = llvm::FunctionType::get(
+ llvm::PointerType::get(DeclTy,
+ Context.getTargetAddressSpace(FD->getType())),
+ false);
+ llvm::Constant *Resolver =
+ GetOrCreateLLVMFunction(ResolverName, ResolverType, GlobalDecl{},
+ /*ForVTable=*/false);
+ llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
+ DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
+ GIF->setName(IFuncName);
+ SetCommonAttributes(FD, GIF);
+
+ return GIF;
+}
+
/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
/// module, create and return an llvm Function with the specified type. If there
/// is something in the module with the specified name, return it potentially
@@ -2074,6 +2215,16 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
ForDefinition_t IsForDefinition) {
const Decl *D = GD.getDecl();
+ // Any attempts to use a MultiVersion function should result in retrieving
+ // the iFunc instead. Name Mangling will handle the rest of the changes.
+ if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D)) {
+ if (FD->isMultiVersion() && FD->getAttr<TargetAttr>()->isDefaultVersion()) {
+ UpdateMultiVersionNames(GD, FD);
+ if (!IsForDefinition)
+ return GetOrCreateMultiVersionIFunc(GD, Ty, MangledName, FD);
+ }
+ }
+
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {