// we have a decl for the function and it has a target attribute then
// parse that and add it to the feature set.
StringRef TargetCPU = getTarget().getTargetOpts().CPU;
-
- // TODO: Features gets us the features on the command line including
- // feature dependencies. For canonicalization purposes we might want to
- // avoid putting features in the target-features set if we know it'll be
- // one of the default features in the backend, e.g. corei7-avx and +avx or
- // figure out non-explicit dependencies.
- // Canonicalize the existing features in a new feature map.
- // TODO: Migrate the existing backends to keep the map around rather than
- // the vector.
- llvm::StringMap<bool> FeatureMap;
- for (auto F : getTarget().getTargetOpts().Features) {
- const char *Name = F.c_str();
- bool Enabled = Name[0] == '+';
- getTarget().setFeatureEnabled(FeatureMap, Name + 1, Enabled);
- }
-
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
- if (FD) {
- if (const auto *TD = FD->getAttr<TargetAttr>()) {
- StringRef FeaturesStr = TD->getFeatures();
- SmallVector<StringRef, 1> AttrFeatures;
- FeaturesStr.split(AttrFeatures, ",");
-
- // Grab the various features and prepend a "+" to turn on the feature to
- // the backend and add them to our existing set of features.
- for (auto &Feature : AttrFeatures) {
- // Go ahead and trim whitespace rather than either erroring or
- // accepting it weirdly.
- Feature = Feature.trim();
-
- // While we're here iterating check for a different target cpu.
- if (Feature.startswith("arch="))
- TargetCPU = Feature.split("=").second.trim();
- else if (Feature.startswith("tune="))
- // We don't support cpu tuning this way currently.
- ;
- else if (Feature.startswith("fpmath="))
- // TODO: Support the fpmath option this way. It will require checking
- // overall feature validity for the function with the rest of the
- // attributes on the function.
- ;
- else if (Feature.startswith("mno-"))
- getTarget().setFeatureEnabled(FeatureMap, Feature.split("-").second,
- false);
- else
- getTarget().setFeatureEnabled(FeatureMap, Feature, true);
- }
+ if (FD && FD->getAttr<TargetAttr>()) {
+ llvm::StringMap<bool> FeatureMap;
+ const auto *TD = FD->getAttr<TargetAttr>();
+
+ // Make a copy of the features as passed on the command line.
+ std::vector<std::string> FnFeatures(
+ getTarget().getTargetOpts().FeaturesAsWritten);
+
+ // Grab the target attribute string.
+ StringRef FeaturesStr = TD->getFeatures();
+ SmallVector<StringRef, 1> AttrFeatures;
+ FeaturesStr.split(AttrFeatures, ",");
+
+ // Grab the various features and prepend a "+" to turn on the feature to
+ // the backend and add them to our existing set of features.
+ for (auto &Feature : AttrFeatures) {
+ // Go ahead and trim whitespace rather than either erroring or
+ // accepting it weirdly.
+ Feature = Feature.trim();
+
+ // While we're here iterating check for a different target cpu.
+ if (Feature.startswith("arch="))
+ TargetCPU = Feature.split("=").second.trim();
+ else if (Feature.startswith("tune="))
+ // We don't support cpu tuning this way currently.
+ ;
+ else if (Feature.startswith("fpmath="))
+ // TODO: Support the fpmath option this way. It will require checking
+ // overall feature validity for the function with the rest of the
+ // attributes on the function.
+ ;
+ else if (Feature.startswith("mno-"))
+ FnFeatures.push_back("-" + Feature.split("-").second.str());
+ else
+ FnFeatures.push_back("+" + Feature.str());
+ }
+ // Now populate the feature map, first with the TargetCPU which is either
+ // the default or a new one from the target attribute string. Then we'll
+ // use the passed in features (FeaturesAsWritten) along with the new ones
+ // from the attribute.
+ getTarget().initDefaultFeatures(FeatureMap, TargetCPU);
+ getTarget().handleUserFeatures(FeatureMap, FnFeatures, Diags);
+
+ // Produce the canonical string for this set of features.
+ std::vector<std::string> Features;
+ for (llvm::StringMap<bool>::const_iterator it = FeatureMap.begin(),
+ ie = FeatureMap.end();
+ it != ie; ++it)
+ Features.push_back((it->second ? "+" : "-") + it->first().str());
+
+ // Now add the target-cpu and target-features to the function.
+ if (TargetCPU != "")
+ FuncAttrs.addAttribute("target-cpu", TargetCPU);
+ if (!Features.empty()) {
+ std::sort(Features.begin(), Features.end());
+ FuncAttrs.addAttribute(
+ "target-features",
+ llvm::join(Features.begin(), Features.end(), ","));
+ }
+ } else {
+ // Otherwise just add the existing target cpu and target features to the
+ // function.
+ std::vector<std::string> &Features = getTarget().getTargetOpts().Features;
+ if (TargetCPU != "")
+ FuncAttrs.addAttribute("target-cpu", TargetCPU);
+ if (!Features.empty()) {
+ std::sort(Features.begin(), Features.end());
+ FuncAttrs.addAttribute(
+ "target-features",
+ llvm::join(Features.begin(), Features.end(), ","));
}
- }
-
- // Produce the canonical string for this set of features.
- std::vector<std::string> Features;
- for (llvm::StringMap<bool>::const_iterator it = FeatureMap.begin(),
- ie = FeatureMap.end();
- it != ie; ++it)
- Features.push_back((it->second ? "+" : "-") + it->first().str());
-
- // Now add the target-cpu and target-features to the function.
- if (TargetCPU != "")
- FuncAttrs.addAttribute("target-cpu", TargetCPU);
- if (!Features.empty()) {
- std::sort(Features.begin(), Features.end());
- FuncAttrs.addAttribute("target-features",
- llvm::join(Features.begin(), Features.end(), ","));
}
}
int bar(int a) { return baz(a) + foo(a); }
int __attribute__((target("avx, sse4.2, arch= ivybridge"))) qux(int a) { return 4; }
+int __attribute__((target("mno-aes, arch=ivybridge"))) qax(int a) { return 4; }
// Check that we emit the additional subtarget and cpu features for foo and not for baz or bar.
// CHECK: baz{{.*}} #0
// CHECK: echidna{{.*}} #2
// CHECK: bar{{.*}} #0
// CHECK: qux{{.*}} #1
+// CHECK: qax{{.*}} #4
// CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,+sse2"
-// CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3"
+// CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+aes,+avx,+cx16,+f16c,+fsgsbase,+pclmul,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3"
// CHECK: #2 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop"
// CHECK: #3 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3"
+// CHECK: #4 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+pclmul,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,-aes"