erichkeane created this revision. erichkeane added reviewers: rsmith, aaron.ballman.
Previously, CPUDispatch functionality did some wacky things with GlobalDecls, which resulted in multiple GlobalDecls having the same mangled name. This patch corrects this in a few ways: First, it Moves the emission of CPUDispatch resolvers to the end of the translation unit. This is akin to how 'target' multiversioning works, and permits the resolver emission mechanism to see all possible FunctionDecls in the TU. Second, it changes the meaning of the GlobalDecl MultiVersionIndex to MultiVersionOrdinal. In the case of CPUSpecific, '0' now means "A call to a non-present CPUDispatch function". Other ordinals are the order of the CPU Name in the attribute source. In the case of CPUDispatch, '0' is the resolver function, and other ordinals represent the non-present CPU-Specific version. Because of this, the 1:1 relationship between a GlobalDecl and a Mangled Name is restored. Additionally, it results in functions only being emitted when necessary, rather than use a variety of hackery to emit in cases we presume they would be used. https://reviews.llvm.org/D55527 Files: include/clang/AST/GlobalDecl.h include/clang/Basic/Attr.td lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h test/CodeGen/attr-cpuspecific.c
Index: test/CodeGen/attr-cpuspecific.c =================================================================== --- test/CodeGen/attr-cpuspecific.c +++ test/CodeGen/attr-cpuspecific.c @@ -29,21 +29,7 @@ ATTR(cpu_dispatch(ivybridge, knl)) void TwoVersions(void); -// LINUX: define void ()* @TwoVersions.resolver() -// LINUX: call void @__cpu_indicator_init -// LINUX: ret void ()* @TwoVersions.Z -// LINUX: ret void ()* @TwoVersions.S -// LINUX: call void @llvm.trap -// LINUX: unreachable - -// WINDOWS: define dso_local void @TwoVersions() -// WINDOWS: call void @__cpu_indicator_init() -// WINDOWS: call void @TwoVersions.Z() -// WINDOWS-NEXT: ret void -// WINDOWS: call void @TwoVersions.S() -// WINDOWS-NEXT: ret void -// WINDOWS: call void @llvm.trap -// WINDOWS: unreachable +// Resolvers are emitted at the end, so the check lines are at the bottom. ATTR(cpu_specific(ivybridge)) void TwoVersions(void){} @@ -82,6 +68,59 @@ // has an extra config to emit! ATTR(cpu_dispatch(ivybridge, knl, atom)) void TwoVersionsSameAttr(void); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, ivybridge, knl)) +void ThreeVersionsSameAttr(void){} +// Resolvers are emitted at the end, so the check lines are at the bottom. + +// No Cpu Specific options. +ATTR(cpu_dispatch(atom, ivybridge, knl)) +void NoSpecifics(void); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) +void HasGeneric(void); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) +void HasParams(int i, double d); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) +int HasParamsAndReturn(int i, double d); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, generic, pentium)) +int GenericAndPentium(int i, double d); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_dispatch(atom, pentium)) +int DispatchFirst(void); +// Resolvers are emitted at the end, so the check lines are at the bottom. + +ATTR(cpu_specific(atom)) +int DispatchFirst(void) {return 0;} +ATTR(cpu_specific(pentium)) +int DispatchFirst(void) {return 1;} +// Resolver emit causes these to be emited, so they happen later. + +// LINUX: define void ()* @TwoVersions.resolver() +// LINUX: call void @__cpu_indicator_init +// LINUX: ret void ()* @TwoVersions.Z +// LINUX: ret void ()* @TwoVersions.S +// LINUX: call void @llvm.trap +// LINUX: unreachable + +// WINDOWS: define dso_local void @TwoVersions() +// WINDOWS: call void @__cpu_indicator_init() +// WINDOWS: call void @TwoVersions.Z() +// WINDOWS-NEXT: ret void +// WINDOWS: call void @TwoVersions.S() +// WINDOWS-NEXT: ret void +// WINDOWS: call void @llvm.trap +// WINDOWS: unreachable + // LINUX: define void ()* @TwoVersionsSameAttr.resolver() // LINUX: ret void ()* @TwoVersionsSameAttr.Z // LINUX: ret void ()* @TwoVersionsSameAttr.S @@ -99,8 +138,6 @@ // WINDOWS: call void @llvm.trap // WINDOWS: unreachable -ATTR(cpu_dispatch(atom, ivybridge, knl)) -void ThreeVersionsSameAttr(void){} // LINUX: define void ()* @ThreeVersionsSameAttr.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @ThreeVersionsSameAttr.Z @@ -120,9 +157,16 @@ // WINDOWS: call void @llvm.trap // WINDOWS: unreachable -// No Cpu Specific options. -ATTR(cpu_dispatch(atom, ivybridge, knl)) -void NoSpecifics(void); +// LINUX: define i32 @DispatchFirst.O +// LINUX: ret i32 0 +// LINUX: define i32 @DispatchFirst.B +// LINUX: ret i32 1 + +// WINDOWS: define dso_local i32 @DispatchFirst.O() +// WINDOWS: ret i32 0 +// WINDOWS: define dso_local i32 @DispatchFirst.B +// WINDOWS: ret i32 1 + // LINUX: define void ()* @NoSpecifics.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @NoSpecifics.Z @@ -142,8 +186,6 @@ // WINDOWS: call void @llvm.trap // WINDOWS: unreachable -ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) -void HasGeneric(void); // LINUX: define void ()* @HasGeneric.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void ()* @HasGeneric.Z @@ -164,8 +206,6 @@ // WINDOWS-NEXT: ret void // WINDOWS-NOT: call void @llvm.trap -ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) -void HasParams(int i, double d); // LINUX: define void (i32, double)* @HasParams.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret void (i32, double)* @HasParams.Z @@ -186,8 +226,6 @@ // WINDOWS-NEXT: ret void // WINDOWS-NOT: call void @llvm.trap -ATTR(cpu_dispatch(atom, generic, ivybridge, knl)) -int HasParamsAndReturn(int i, double d); // LINUX: define i32 (i32, double)* @HasParamsAndReturn.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret i32 (i32, double)* @HasParamsAndReturn.Z @@ -208,8 +246,6 @@ // WINDOWS-NEXT: ret i32 %[[RET]] // WINDOWS-NOT: call void @llvm.trap -ATTR(cpu_dispatch(atom, generic, pentium)) -int GenericAndPentium(int i, double d); // LINUX: define i32 (i32, double)* @GenericAndPentium.resolver() // LINUX: call void @__cpu_indicator_init // LINUX: ret i32 (i32, double)* @GenericAndPentium.O @@ -226,8 +262,6 @@ // WINDOWS-NOT: call i32 @GenericAndPentium.A // WINDOWS-NOT: call void @llvm.trap -ATTR(cpu_dispatch(atom, pentium)) -int DispatchFirst(void); // LINUX: define i32 ()* @DispatchFirst.resolver // LINUX: ret i32 ()* @DispatchFirst.O // LINUX: ret i32 ()* @DispatchFirst.B @@ -238,22 +272,6 @@ // WINDOWS: %[[RET:.+]] = musttail call i32 @DispatchFirst.B() // WINDOWS-NEXT: ret i32 %[[RET]] -ATTR(cpu_specific(atom)) -int DispatchFirst(void) {return 0;} -// LINUX: define i32 @DispatchFirst.O -// LINUX: ret i32 0 - -// WINDOWS: define dso_local i32 @DispatchFirst.O() -// WINDOWS: ret i32 0 - -ATTR(cpu_specific(pentium)) -int DispatchFirst(void) {return 1;} -// LINUX: define i32 @DispatchFirst.B -// LINUX: ret i32 1 - -// WINDOWS: define dso_local i32 @DispatchFirst.B -// WINDOWS: ret i32 1 - // CHECK: attributes #[[S]] = {{.*}}"target-features"="+avx,+cmov,+f16c,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave" // CHECK: attributes #[[K]] = {{.*}}"target-features"="+adx,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+bmi,+cmov,+f16c,+fma,+lzcnt,+mmx,+movbe,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave" // CHECK: attributes #[[O]] = {{.*}}"target-features"="+cmov,+mmx,+movbe,+sse,+sse2,+sse3,+ssse3,+x87" Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1324,7 +1324,10 @@ void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); void EmitAliasDefinition(GlobalDecl GD); void emitIFuncDefinition(GlobalDecl GD); - void emitCPUDispatchDefinition(GlobalDecl GD); + void emitTargetMultiVersionResolver(GlobalDecl GD); + llvm::Function *getCPUDispatchResolverFunction(GlobalDecl GD, + llvm::Type *&DeclTy); + void emitCPUDispatchResolver(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -894,13 +894,18 @@ static void AppendCPUSpecificCPUDispatchMangling(const CodeGenModule &CGM, const CPUSpecificAttr *Attr, - unsigned CPUIndex, + unsigned CPUOrdinal, raw_ostream &Out) { // cpu_specific gets the current name, dispatch gets the resolver if IFunc is // supported. - if (Attr) - Out << getCPUSpecificMangling(CGM, Attr->getCPUName(CPUIndex)->getName()); - else if (CGM.getTarget().supportsIFunc()) + if (Attr && CPUOrdinal) + Out << getCPUSpecificMangling(CGM, Attr->getCPUName(CPUOrdinal)->getName()); + else if (Attr && !CPUOrdinal) { + // If this is a CPUSpecific function as a callee, make sure we give it the + // 'ifunc' name (in IFunc mode) else the resolver name. + if (CGM.getTarget().supportsIFunc()) + Out << ".ifunc"; + } else if (CGM.getTarget().supportsIFunc()) Out << ".resolver"; } @@ -971,7 +976,7 @@ case MultiVersionKind::CPUSpecific: AppendCPUSpecificCPUDispatchMangling(CGM, FD->getAttr<CPUSpecificAttr>(), - GD.getMultiVersionIndex(), Out); + GD.getMultiVersionOrdinal(), Out); break; case MultiVersionKind::Target: AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out); @@ -2125,9 +2130,19 @@ if (Global->hasAttr<IFuncAttr>()) return emitIFuncDefinition(GD); - // If this is a cpu_dispatch multiversion function, emit the resolver. - if (Global->hasAttr<CPUDispatchAttr>()) - return emitCPUDispatchDefinition(GD); + // If this is a cpu_dispatch multiversion function, designate it for emission + // at the end of the Translation Unit. + if (Global->hasAttr<CPUDispatchAttr>()) { + MultiVersionFuncs.push_back(GD); + return; + } + + if (Global->hasAttr<CPUSpecificAttr>() && GD.getMultiVersionOrdinal() == 0) { + auto *Spec = Global->getAttr<CPUSpecificAttr>(); + for (unsigned I = 1; I <= Spec->cpus_size(); ++I) + EmitGlobal(GD.getWithMultiVersionOrdinal(I)); + return; + } // If this is CUDA, be selective about which declarations we emit. if (LangOpts.CUDA) { @@ -2423,10 +2438,10 @@ const auto *FD = cast<FunctionDecl>(GD.getDecl()); if (FD->isCPUSpecificMultiVersion()) { - auto *Spec = FD->getAttr<CPUSpecificAttr>(); - for (unsigned I = 0; I < Spec->cpus_size(); ++I) - EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); // Requires multiple emits. + auto *Spec = FD->getAttr<CPUSpecificAttr>(); + for (unsigned I = 1; I <= Spec->cpus_size(); ++I) + EmitGlobalFunctionDefinition(GD.getWithMultiVersionOrdinal(I), nullptr); } else EmitGlobalFunctionDefinition(GD, GV); } @@ -2489,129 +2504,164 @@ return Priority; } -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"); +void CodeGenModule::emitTargetMultiVersionResolver(GlobalDecl GD) { + SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options; + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + assert(FD->isTargetMultiVersion() && "Not a target multiversion function?"); + + 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"); + } - const auto *TA = CurFD->getAttr<TargetAttr>(); - llvm::SmallVector<StringRef, 8> Feats; - TA->getAddedFeatures(Feats); + const auto *TA = CurFD->getAttr<TargetAttr>(); + llvm::SmallVector<StringRef, 8> Feats; + TA->getAddedFeatures(Feats); - Options.emplace_back(cast<llvm::Function>(Func), - TA->getArchitecture(), Feats); - }); + Options.emplace_back(cast<llvm::Function>(Func), TA->getArchitecture(), + Feats); + }); + llvm::Function *ResolverFunc; + const TargetInfo &TI = getTarget(); - llvm::Function *ResolverFunc; - const TargetInfo &TI = getTarget(); + if (TI.supportsIFunc() || FD->isTargetMultiVersion()) + ResolverFunc = cast<llvm::Function>( + GetGlobalValue((getMangledName(GD) + ".resolver").str())); + else + ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD))); - if (TI.supportsIFunc() || FD->isTargetMultiVersion()) - ResolverFunc = cast<llvm::Function>( - GetGlobalValue((getMangledName(GD) + ".resolver").str())); - else - ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD))); + if (supportsCOMDAT()) + ResolverFunc->setComdat( + getModule().getOrInsertComdat(ResolverFunc->getName())); + + std::stable_sort( + Options.begin(), Options.end(), + [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS, + const CodeGenFunction::MultiVersionResolverOption &RHS) { + return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS); + }); + CodeGenFunction CGF(*this); + CGF.EmitMultiVersionResolver(ResolverFunc, Options); +} - if (supportsCOMDAT()) - ResolverFunc->setComdat( - getModule().getOrInsertComdat(ResolverFunc->getName())); +void CodeGenModule::emitMultiVersionFunctions() { + for (GlobalDecl GD : MultiVersionFuncs) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + assert(FD && FD->isMultiVersion() && "Not a multiversion function?"); - std::stable_sort( - Options.begin(), Options.end(), - [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS, - const CodeGenFunction::MultiVersionResolverOption &RHS) { - return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS); - }); - CodeGenFunction CGF(*this); - CGF.EmitMultiVersionResolver(ResolverFunc, Options); + switch (FD->getMultiVersionKind()) { + case MultiVersionKind::Target: + emitTargetMultiVersionResolver(GD); + break; + case MultiVersionKind::CPUDispatch: + emitCPUDispatchResolver(GD); + break; + case MultiVersionKind::CPUSpecific: + case MultiVersionKind::None: + llvm_unreachable("Function does not cause a multiversion resolver."); + } } } -void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { - const auto *FD = cast<FunctionDecl>(GD.getDecl()); - assert(FD && "Not a FunctionDecl?"); - const auto *DD = FD->getAttr<CPUDispatchAttr>(); - assert(DD && "Not a cpu_dispatch Function?"); +// Helper function to get the llvm::Function object for the resolver so that +// it can be filled in. +llvm::Function * +CodeGenModule::getCPUDispatchResolverFunction(GlobalDecl GD, + llvm::Type *&DeclTy) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); QualType CanonTy = Context.getCanonicalType(FD->getType()); - llvm::Type *DeclTy = getTypes().ConvertFunctionType(CanonTy, FD); - + DeclTy = getTypes().ConvertFunctionType(CanonTy, FD); if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) { - const CGFunctionInfo &FInfo = getTypes().arrangeCXXMethodDeclaration(CXXFD); + const CGFunctionInfo &FInfo = + getTypes().arrangeCXXMethodDeclaration(CXXFD); DeclTy = getTypes().GetFunctionType(FInfo); } - StringRef ResolverName = getMangledName(GD); - llvm::Type *ResolverType; GlobalDecl ResolverGD; if (getTarget().supportsIFunc()) ResolverType = llvm::FunctionType::get( - llvm::PointerType::get(DeclTy, - Context.getTargetAddressSpace(FD->getType())), + llvm::PointerType::get( + DeclTy, getContext().getTargetAddressSpace(FD->getType())), false); else { ResolverType = DeclTy; ResolverGD = GD; } - auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction( + return cast<llvm::Function>(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); +} +void CodeGenModule::emitCPUDispatchResolver(GlobalDecl GD) { SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options; const TargetInfo &Target = getTarget(); - unsigned Index = 0; + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + assert(FD->isCPUDispatchMultiVersion() && + "Not a target multiversion function?"); + const auto *DD = FD->getAttr<CPUDispatchAttr>(); + llvm::Type *DeclTy = nullptr; + llvm::Function *ResolverFunc = getCPUDispatchResolverFunction(GD, DeclTy); + + unsigned Ordinal = 1; for (const IdentifierInfo *II : DD->cpus()) { - // Get the name of the target function so we can look it up/create it. - std::string MangledName = getMangledNameImpl(*this, GD, FD, true) + - getCPUSpecificMangling(*this, II->getName()); - - llvm::Constant *Func = GetGlobalValue(MangledName); - - if (!Func) { - GlobalDecl ExistingDecl = Manglings.lookup(MangledName); - if (ExistingDecl.getDecl() && - ExistingDecl.getDecl()->getAsFunction()->isDefined()) { - EmitGlobalFunctionDefinition(ExistingDecl, nullptr); - Func = GetGlobalValue(MangledName); - } else { - if (!ExistingDecl.getDecl()) - ExistingDecl = GD.getWithMultiVersionIndex(Index); + GlobalDecl ImplDecl; + // If the function version was declared/defined in the translation unit, use + // that one. + getContext().forEachMultiversionedFunctionVersion( + FD, [&ImplDecl, II](const FunctionDecl *CurFD) { + CPUSpecificAttr *SA = CurFD->getAttr<CPUSpecificAttr>(); + unsigned Ord; + if (SA && (Ord = SA->getCPUNameOrdinal(II->getName()))) + ImplDecl = + GlobalDecl(CurFD->isDefined() ? CurFD->getDefinition() + : CurFD->getCanonicalDecl(), + Ord); + }); + + llvm::Function *Func = nullptr; + if (!ImplDecl.getDecl()) { + ImplDecl = GD.getWithMultiVersionOrdinal(Ordinal); - Func = GetOrCreateLLVMFunction( - MangledName, DeclTy, ExistingDecl, + std::string MangledName = getMangledNameImpl(*this, ImplDecl, FD, true) + + getCPUSpecificMangling(*this, II->getName()); + Func = cast<llvm::Function>(GetOrCreateLLVMFunction( + MangledName, DeclTy, ImplDecl, /*ForVTable=*/false, /*DontDefer=*/true, - /*IsThunk=*/false, llvm::AttributeList(), ForDefinition); - } + /*IsThunk=*/false, llvm::AttributeList(), ForDefinition)); + } else { + if (ImplDecl.getDecl()->getAsFunction()->isDefined()) + EmitGlobalFunctionDefinition(ImplDecl, nullptr); + std::string MangledName = getMangledNameImpl( + *this, ImplDecl, ImplDecl.getDecl()->getAsFunction(), false); + Func = cast<llvm::Function>(GetGlobalValue(MangledName)); } + assert(Func && "This should have just been created"); llvm::SmallVector<StringRef, 32> Features; Target.getCPUSpecificCPUDispatchFeatures(II->getName(), Features); llvm::transform(Features, Features.begin(), [](StringRef Str) { return Str.substr(1); }); - Features.erase(std::remove_if( - Features.begin(), Features.end(), [&Target](StringRef Feat) { - return !Target.validateCpuSupports(Feat); - }), Features.end()); + Features.erase(std::remove_if(Features.begin(), Features.end(), + [&Target](StringRef Feat) { + return !Target.validateCpuSupports(Feat); + }), + Features.end()); Options.emplace_back(cast<llvm::Function>(Func), StringRef{}, Features); - ++Index; + ++Ordinal; } llvm::sort( @@ -2620,7 +2670,6 @@ return CodeGenFunction::GetX86CpuSupportsMask(LHS.Conditions.Features) > CodeGenFunction::GetX86CpuSupportsMask(RHS.Conditions.Features); }); - // If the list contains multiple 'default' versions, such as when it contains // 'pentium' and 'generic', don't emit the call to the generic one (since we // always run on at least a 'pentium'). We do this by deleting the 'least @@ -5450,7 +5499,7 @@ } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) { llvm::SmallVector<StringRef, 32> FeaturesTmp; Target.getCPUSpecificCPUDispatchFeatures( - SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); + SD->getCPUName(GD.getMultiVersionOrdinal())->getName(), FeaturesTmp); std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end()); Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, Features); } else { Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -893,8 +893,21 @@ let Subjects = SubjectList<[Function]>; let Documentation = [CPUSpecificCPUDispatchDocs]; let AdditionalMembers = [{ - IdentifierInfo *getCPUName(unsigned Index) const { - return *(cpus_begin() + Index); + // gets the ordinal of the requested CPU name, or 0 if it isn't in the cpu + // list. + unsigned getCPUNameOrdinal(StringRef Name) const { + unsigned Ord = 1; + for (const IdentifierInfo *II : cpus()) { + if (II->getName() == Name) + return Ord; + ++Ord; + } + return 0; + } + + IdentifierInfo *getCPUName(unsigned Ordinal) const { + assert(Ordinal > 0 && "Invalid Ordinal"); + return *(cpus_begin() + Ordinal - 1); } }]; } Index: include/clang/AST/GlobalDecl.h =================================================================== --- include/clang/AST/GlobalDecl.h +++ include/clang/AST/GlobalDecl.h @@ -34,7 +34,7 @@ /// a VarDecl, a FunctionDecl or a BlockDecl. class GlobalDecl { llvm::PointerIntPair<const Decl *, 2> Value; - unsigned MultiVersionIndex = 0; + unsigned MultiVersionOrdinal = 0; void Init(const Decl *D) { assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); @@ -46,8 +46,8 @@ public: GlobalDecl() = default; GlobalDecl(const VarDecl *D) { Init(D);} - GlobalDecl(const FunctionDecl *D, unsigned MVIndex = 0) - : MultiVersionIndex(MVIndex) { + GlobalDecl(const FunctionDecl *D, unsigned MVOrd = 0) + : MultiVersionOrdinal(MVOrd) { Init(D); } GlobalDecl(const BlockDecl *D) { Init(D); } @@ -61,7 +61,7 @@ GlobalDecl CanonGD; CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl()); CanonGD.Value.setInt(Value.getInt()); - CanonGD.MultiVersionIndex = MultiVersionIndex; + CanonGD.MultiVersionOrdinal = MultiVersionOrdinal; return CanonGD; } @@ -78,17 +78,17 @@ return static_cast<CXXDtorType>(Value.getInt()); } - unsigned getMultiVersionIndex() const { + unsigned getMultiVersionOrdinal() const { assert(isa<FunctionDecl>(getDecl()) && !isa<CXXConstructorDecl>(getDecl()) && !isa<CXXDestructorDecl>(getDecl()) && "Decl is not a plain FunctionDecl!"); - return MultiVersionIndex; + return MultiVersionOrdinal; } friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { return LHS.Value == RHS.Value && - LHS.MultiVersionIndex == RHS.MultiVersionIndex; + LHS.MultiVersionOrdinal== RHS.MultiVersionOrdinal; } void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } @@ -105,13 +105,13 @@ return Result; } - GlobalDecl getWithMultiVersionIndex(unsigned Index) { + GlobalDecl getWithMultiVersionOrdinal(unsigned Ordinal) { assert(isa<FunctionDecl>(getDecl()) && !isa<CXXConstructorDecl>(getDecl()) && !isa<CXXDestructorDecl>(getDecl()) && "Decl is not a plain FunctionDecl!"); GlobalDecl Result(*this); - Result.MultiVersionIndex = Index; + Result.MultiVersionOrdinal = Ordinal; return Result; } };
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits