let Documentation = [Undocumented];
}
+def Target : InheritableAttr {
+ let Spellings = [GCC<"target">];
+ let Args = [StringArgument<"features">];
+ let Subjects =
+ SubjectList<[Function], ErrorDiag, "ExpectedFunctionMethodOrClass">;
+ let Documentation = [Undocumented];
+}
+
def TransparentUnion : InheritableAttr {
let Spellings = [GCC<"transparent_union">];
// let Subjects = SubjectList<[Record, TypedefName]>;
if (!CodeGenOpts.StackRealignment)
FuncAttrs.addAttribute("no-realign-stack");
- // Add target-cpu and target-features work if they differ from the defaults.
- std::string &CPU = getTarget().getTargetOpts().CPU;
- if (CPU != "")
- FuncAttrs.addAttribute("target-cpu", CPU);
+ // Add target-cpu and target-features attributes to functions. If
+ // 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.
- std::vector<std::string> &Features = getTarget().getTargetOpts().Features;
+ // 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.
+ std::vector<std::string> Features(getTarget().getTargetOpts().Features);
+
+ // TODO: The target attribute complicates this further by allowing multiple
+ // additional features to be tacked on to the feature string for a
+ // particular function. For now we simply append to the set of features and
+ // let backend resolution fix them up.
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
+ if (FD) {
+ if (const TargetAttr *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) {
+ // While we're here iterating check for a different target cpu.
+ if (Feature.startswith("arch="))
+ TargetCPU = Feature.split("=").second;
+ else
+ Features.push_back("+" + Feature.str());
+ }
+ }
+ }
+
+ // Now add the target-cpu and target-features to the function.
+ if (TargetCPU != "")
+ FuncAttrs.addAttribute("target-cpu", TargetCPU);
if (!Features.empty()) {
- std::stringstream S;
+ std::stringstream TargetFeatures;
std::copy(Features.begin(), Features.end(),
- std::ostream_iterator<std::string>(S, ","));
+ std::ostream_iterator<std::string>(TargetFeatures, ","));
+
// The drop_back gets rid of the trailing space.
FuncAttrs.addAttribute("target-features",
- StringRef(S.str()).drop_back(1));
+ StringRef(TargetFeatures.str()).drop_back(1));
}
}
D->addAttr(NewAttr);
}
+static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // TODO: Validation should use a backend target library that specifies
+ // the allowable subtarget features and cpus. We could use something like a
+ // TargetCodeGenInfo hook here to do validation.
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
+ return;
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ TargetAttr *NewAttr =
+ ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index);
+ D->addAttr(NewAttr);
+}
+
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
VarDecl *VD = cast<VarDecl>(D);
case AttributeList::AT_Section:
handleSectionAttr(S, D, Attr);
break;
+ case AttributeList::AT_Target:
+ handleTargetAttr(S, D, Attr);
+ break;
case AttributeList::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, Attr);
break;
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -target-cpu x86-64 -emit-llvm %s -o - | FileCheck %s
+
+int baz(int a) { return 4; }
+
+int __attribute__((target("avx,sse4.2,arch=ivybridge"))) foo(int a) { return 4; }
+
+int bar(int a) { return baz(a) + foo(a); }
+
+// Check that we emit the additional subtarget and cpu features for foo and not for baz or bar.
+// CHECK: baz{{.*}} #0
+// CHECK: foo{{.*}} #1
+// CHECK: bar{{.*}} #0
+// CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+sse,+sse2"
+// CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+sse,+sse2,+avx,+sse4.2"