]> granicus.if.org Git - clang/commitdiff
Rewrite the code generation handling for function feature and cpu attributes.
authorEric Christopher <echristo@gmail.com>
Thu, 27 Aug 2015 19:59:34 +0000 (19:59 +0000)
committerEric Christopher <echristo@gmail.com>
Thu, 27 Aug 2015 19:59:34 +0000 (19:59 +0000)
A couple of changes here:

a) Do less work in the case where we don't have a target attribute on the
function. We've already canonicalized the attributes for the function -
no need to do more work.

b) Use the newer canonicalized feature adding functions from TargetInfo
to do the work when we do have a target attribute. This enables us to diagnose
some warnings in the case of conflicting written attributes (only ppc does
this today) and also make sure to get all of the features for a cpu that's
listed rather than just change the cpu.

Updated all testcases accordingly and added a new testcase to verify that we'll
error out on ppc if we have some incompatible options using the existing diagnosis
framework there.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@246195 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
test/CodeGen/attr-target-ppc.c [new file with mode: 0644]
test/CodeGen/attr-target.c

index f40dd0864818c7f0121ec2b182400ac6fd7bfc9e..eff9fde8393a86c00192d101ececbd085a10058c 100644 (file)
@@ -1496,70 +1496,78 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
     // 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(), ","));
     }
   }
 
diff --git a/test/CodeGen/attr-target-ppc.c b/test/CodeGen/attr-target-ppc.c
new file mode 100644 (file)
index 0000000..c98c70a
--- /dev/null
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -triple powerpc64le-linux-gnu -emit-llvm %s -o -
+
+long __attribute__((target("power8-vector,mno-vsx"))) foo (void) { return 0; }  // expected-error {{option '-mpower8-vector' cannot be specified with '-mno-vsx'}}
+
index d805d133f365f5cf859d92f19f6c7457d4eb35f4..b02dd7196508af3ff71374cf82135f788ffce2a4 100644 (file)
@@ -14,6 +14,7 @@ int __attribute__((target("sse4"))) panda(int a) { return 4; }
 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
@@ -25,7 +26,9 @@ int __attribute__((target("avx,      sse4.2,      arch=   ivybridge"))) qux(int
 // 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"