<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 11, 2015 at 4:44 PM, Eric Christopher via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: echristo<br>
Date: Wed Nov 11 18:44:12 2015<br>
New Revision: 252834<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=252834&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=252834&view=rev</a><br>
Log:<br>
Provide a frontend based error for always_inline functions that require<br>
target features that the caller function doesn't provide. This matches<br>
the existing backend failure to inline functions that don't have<br>
matching target features - and diagnoses earlier in the case of<br>
always_inline.<br>
<br>
Fix up a few test cases that were, in fact, invalid if you tried<br>
to generate code from the backend with the specified target features<br>
and add a couple of tests to illustrate what's going on.<br>
<br>
This should fix PR25246.<br>
<br>
Added:<br>
    cfe/trunk/test/CodeGen/target-features-error-2.c<br>
    cfe/trunk/test/CodeGen/target-features-error.c<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
    cfe/trunk/test/CodeGen/3dnow-builtins.c<br>
    cfe/trunk/test/CodeGen/avx512vl-builtins.c<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=252834&r1=252833&r2=252834&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=252834&r1=252833&r2=252834&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Nov 11 18:44:12 2015<br>
@@ -431,6 +431,9 @@ def err_builtin_definition : Error<"defi<br>
 def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;<br>
 def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">;<br>
 def err_builtin_needs_feature : Error<"%0 needs target feature %1">;<br>
+def err_function_needs_feature<br>
+    : Error<"function %0 and always_inline callee function %1 are required to "<br>
+            "have matching target features">;<br>
 def warn_builtin_unknown : Warning<"use of unknown builtin %0">,<br>
   InGroup<ImplicitFunctionDeclare>, DefaultError;<br>
 def warn_dyn_class_memaccess : Warning<<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=252834&r1=252833&r2=252834&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=252834&r1=252833&r2=252834&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Nov 11 18:44:12 2015<br>
@@ -3747,6 +3747,15 @@ RValue CodeGenFunction::EmitCall(QualTyp<br>
   assert(CalleeType->isFunctionPointerType() &&<br>
          "Call must have function pointer type!");<br>
<br>
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))<br>
+    // If this isn't an always_inline function we can't guarantee that any<br>
+    // function isn't being used correctly so only check if we have the<br>
+    // attribute and a set of target attributes that might be different from<br>
+    // our default.<br>
+    if (TargetDecl->hasAttr<AlwaysInlineAttr>() &&<br>
+        TargetDecl->hasAttr<TargetAttr>())<br>
+      checkTargetFeatures(E, FD);<br>
+<br>
   CalleeType = getContext().getCanonicalType(CalleeType);<br>
<br>
   const auto *FnType =<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=252834&r1=252833&r2=252834&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=252834&r1=252833&r2=252834&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Nov 11 18:44:12 2015<br>
@@ -1843,7 +1843,8 @@ template void CGBuilderInserter<Preserve<br>
     llvm::BasicBlock::iterator InsertPt) const;<br>
 #undef PreserveNames<br>
<br>
-// Returns true if we have a valid set of target features.<br>
+// Emits an error if we don't have a valid set of target features for the<br>
+// called function.<br>
 void CodeGenFunction::checkTargetFeatures(const CallExpr *E,<br>
                                           const FunctionDecl *TargetDecl) {<br>
   // Early exit if this is an indirect call.<br>
@@ -1856,31 +1857,70 @@ void CodeGenFunction::checkTargetFeature<br>
   if (!FD)<br>
     return;<br>
<br>
+  // Grab the required features for the call. For a builtin this is listed in<br>
+  // the td file with the default cpu, for an always_inline function this is any<br>
+  // listed cpu and any listed features.<br>
   unsigned BuiltinID = TargetDecl->getBuiltinID();<br>
-  const char *FeatureList =<br>
-      CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);<br>
-<br>
-  if (!FeatureList || StringRef(FeatureList) == "")<br>
-    return;<br>
-<br>
-  llvm::StringMap<bool> FeatureMap;<br>
-  CGM.getFunctionFeatureMap(FeatureMap, FD);<br>
-<br>
-  // If we have at least one of the features in the feature list return<br>
-  // true, otherwise return false.<br>
-  SmallVector<StringRef, 1> AttrFeatures;<br>
-  StringRef(FeatureList).split(AttrFeatures, ",");<br>
-  if (!std::all_of(AttrFeatures.begin(), AttrFeatures.end(),<br>
-                     [&](StringRef &Feature) {<br>
-                       SmallVector<StringRef, 1> OrFeatures;<br>
-                       Feature.split(OrFeatures, "|");<br>
-                       return std::any_of(OrFeatures.begin(), OrFeatures.end(),<br>
-                                          [&](StringRef &Feature) {<br>
-                                            return FeatureMap[Feature];<br>
-                                          });<br>
-                  }))<br>
-    CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature)<br>
-        << TargetDecl->getDeclName()<br>
-        << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);<br>
+  if (BuiltinID) {<br>
+    SmallVector<StringRef, 1> ReqFeatures;<br>
+    const char *FeatureList =<br>
+        CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);<br>
+    // Return if the builtin doesn't have any required features.<br>
+    if (!FeatureList || StringRef(FeatureList) == "")<br>
+      return;<br>
+    StringRef(FeatureList).split(ReqFeatures, ",");<br>
+<br></blockquote><div><br></div><div>Looks like from here on down to the end of the scope matches the tail of the else if clause (except for the actual diag code) - perhaps pull it out as a common function that returns bool & call that to then decide on the diagnostic?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+    // If there aren't any required features listed then go ahead and return.<br>
+    if (ReqFeatures.empty())<br>
+      return;<br>
+<br>
+    // Now build up the set of caller features and verify that all the required<br>
+    // features are there.<br>
+    llvm::StringMap<bool> CallerFeatureMap;<br>
+    CGM.getFunctionFeatureMap(CallerFeatureMap, FD);<br>
+<br>
+    // If we have at least one of the features in the feature list return<br>
+    // true, otherwise return false.<br>
+    if (!std::all_of(<br>
+            ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef &Feature) {<br>
+              SmallVector<StringRef, 1> OrFeatures;<br>
+              Feature.split(OrFeatures, "|");<br>
+              return std::any_of(OrFeatures.begin(), OrFeatures.end(),<br>
+                                 [&](StringRef &Feature) {<br>
+                                   return CallerFeatureMap.lookup(Feature);<br>
+                                 });<br>
+            }))<br>
+      CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature)<br>
+          << TargetDecl->getDeclName()<br>
+          << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);<br>
+<br>
+  } else if (TargetDecl->hasAttr<TargetAttr>()) {<br>
+    // Get the required features for the callee.<br>
+    SmallVector<StringRef, 1> ReqFeatures;<br>
+    llvm::StringMap<bool> CalleeFeatureMap;<br>
+    CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);<br>
+    for (const auto &F : CalleeFeatureMap)<br>
+      ReqFeatures.push_back(F.getKey());<br>
+    // If there aren't any required features listed then go ahead and return.<br>
+    if (ReqFeatures.empty())<br>
+      return;<br>
+<br>
+    // Now get the features that the caller provides.<br>
+    llvm::StringMap<bool> CallerFeatureMap;<br>
+    CGM.getFunctionFeatureMap(CallerFeatureMap, FD);<br>
+<br>
+    // If we have at least one of the features in the feature list return<br>
+    // true, otherwise return false.<br>
+    if (!std::all_of(<br>
+            ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef &Feature) {<br>
+              SmallVector<StringRef, 1> OrFeatures;<br>
+              Feature.split(OrFeatures, "|");<br>
+              return std::any_of(OrFeatures.begin(), OrFeatures.end(),<br>
+                                 [&](StringRef &Feature) {<br>
+                                   return CallerFeatureMap.lookup(Feature);<br>
+                                 });<br>
+            }))<br>
+      CGM.getDiags().Report(E->getLocStart(), diag::err_function_needs_feature)<br>
+          << FD->getDeclName() << TargetDecl->getDeclName();<br>
+  }<br>
 }<br>
-<br>
<br>
Modified: cfe/trunk/test/CodeGen/3dnow-builtins.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/3dnow-builtins.c?rev=252834&r1=252833&r2=252834&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/3dnow-builtins.c?rev=252834&r1=252833&r2=252834&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/3dnow-builtins.c (original)<br>
+++ cfe/trunk/test/CodeGen/3dnow-builtins.c Wed Nov 11 18:44:12 2015<br>
@@ -1,6 +1,6 @@<br>
 // REQUIRES: x86-registered-target<br>
-// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnow -emit-llvm -o - -Werror | FileCheck %s<br>
-// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnow -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM<br>
+// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnowa -emit-llvm -o - -Werror | FileCheck %s<br>
+// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -target-feature +3dnowa -S -o - -Werror | FileCheck %s --check-prefix=CHECK-ASM<br>
<br>
 // Don't include mm_malloc.h, it's system specific.<br>
 #define __MM_MALLOC_H<br>
<br>
Modified: cfe/trunk/test/CodeGen/avx512vl-builtins.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/avx512vl-builtins.c?rev=252834&r1=252833&r2=252834&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/avx512vl-builtins.c?rev=252834&r1=252833&r2=252834&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/avx512vl-builtins.c (original)<br>
+++ cfe/trunk/test/CodeGen/avx512vl-builtins.c Wed Nov 11 18:44:12 2015<br>
@@ -5,102 +5,6 @@<br>
<br>
 #include <immintrin.h><br>
<br>
-__mmask8 test_mm256_cmpeq_epi32_mask(__m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_cmpeq_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256<br>
-  return (__mmask8)_mm256_cmpeq_epi32_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_mask_cmpeq_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_mask_cmpeq_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.256<br>
-  return (__mmask8)_mm256_mask_cmpeq_epi32_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_cmpeq_epi32_mask(__m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_cmpeq_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128<br>
-  return (__mmask8)_mm_cmpeq_epi32_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_mask_cmpeq_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_mask_cmpeq_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.d.128<br>
-  return (__mmask8)_mm_mask_cmpeq_epi32_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_cmpeq_epi64_mask(__m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_cmpeq_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256<br>
-  return (__mmask8)_mm256_cmpeq_epi64_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_mask_cmpeq_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_mask_cmpeq_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.256<br>
-  return (__mmask8)_mm256_mask_cmpeq_epi64_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_cmpeq_epi64_mask(__m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_cmpeq_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128<br>
-  return (__mmask8)_mm_cmpeq_epi64_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_mask_cmpeq_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_mask_cmpeq_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpeq.q.128<br>
-  return (__mmask8)_mm_mask_cmpeq_epi64_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_cmpgt_epi32_mask(__m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_cmpgt_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.256<br>
-  return (__mmask8)_mm256_cmpgt_epi32_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_mask_cmpgt_epi32_mask(__mmask8 __u, __m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_mask_cmpgt_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.256<br>
-  return (__mmask8)_mm256_mask_cmpgt_epi32_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_cmpgt_epi32_mask(__m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_cmpgt_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.128<br>
-  return (__mmask8)_mm_cmpgt_epi32_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_mask_cmpgt_epi32_mask(__mmask8 __u, __m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_mask_cmpgt_epi32_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.d.128<br>
-  return (__mmask8)_mm_mask_cmpgt_epi32_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_cmpgt_epi64_mask(__m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_cmpgt_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.256<br>
-  return (__mmask8)_mm256_cmpgt_epi64_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm256_mask_cmpgt_epi64_mask(__mmask8 __u, __m256i __a, __m256i __b) {<br>
-  // CHECK-LABEL: @test_mm256_mask_cmpgt_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.256<br>
-  return (__mmask8)_mm256_mask_cmpgt_epi64_mask(__u, __a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_cmpgt_epi64_mask(__m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_cmpgt_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.128<br>
-  return (__mmask8)_mm_cmpgt_epi64_mask(__a, __b);<br>
-}<br>
-<br>
-__mmask8 test_mm_mask_cmpgt_epi64_mask(__mmask8 __u, __m128i __a, __m128i __b) {<br>
-  // CHECK-LABEL: @test_mm_mask_cmpgt_epi64_mask<br>
-  // CHECK: @llvm.x86.avx512.mask.pcmpgt.q.128<br>
-  return (__mmask8)_mm_mask_cmpgt_epi64_mask(__u, __a, __b);<br>
-}<br>
-<br>
 __mmask8 test_mm_cmpeq_epu32_mask(__m128i __a, __m128i __b) {<br>
   // CHECK-LABEL: @test_mm_cmpeq_epu32_mask<br>
   // CHECK: @llvm.x86.avx512.mask.ucmp.d.128(<4 x i32> {{.*}}, <4 x i32> {{.*}}, i32 0, i8 -1)<br>
<br>
Added: cfe/trunk/test/CodeGen/target-features-error-2.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/target-features-error-2.c?rev=252834&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/target-features-error-2.c?rev=252834&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/target-features-error-2.c (added)<br>
+++ cfe/trunk/test/CodeGen/target-features-error-2.c Wed Nov 11 18:44:12 2015<br>
@@ -0,0 +1,7 @@<br>
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o -<br>
+#define __MM_MALLOC_H<br>
+#include <x86intrin.h><br>
+<br>
+int baz(__m256i a) {<br>
+  return _mm256_extract_epi32(a, 3); // expected-error {{function 'baz' and always_inline callee function '_mm256_extract_epi32' are required to have matching target features}}<br>
+}<br>
<br>
Added: cfe/trunk/test/CodeGen/target-features-error.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/target-features-error.c?rev=252834&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/target-features-error.c?rev=252834&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/target-features-error.c (added)<br>
+++ cfe/trunk/test/CodeGen/target-features-error.c Wed Nov 11 18:44:12 2015<br>
@@ -0,0 +1,8 @@<br>
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o -<br>
+int __attribute__((target("avx"), always_inline)) foo(int a) {<br>
+  return a + 4;<br>
+}<br>
+int bar() {<br>
+  return foo(4); // expected-error {{function 'bar' and always_inline callee function 'foo' are required to have matching target features}}<br>
+}<br>
+<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>