<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Wed, Nov 11, 2015 at 5:03 PM Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><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></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><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></blockquote><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>It would be useful to say which feature is missing here. Also, "matching" implies to </div></div></div></div></blockquote><div><br></div><div>Right. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>me that the sets must be the same, whereas I think the rule is that the caller must at least all the features that the callee uses. Something like: "always_inline callee function %0 uses target feature %1 that caller %2 does not require" might be more useful?</div></div></div></div></blockquote><div><br></div><div>So, I was waiting on this I admit :)</div><div><br></div><div>What we really need is a "string set" way of doing set difference and then optionally translating that to command line options. I'm really leery of doing the "full set of options missing" though due to just the sheer size of the error messages out the other end. i.e. "default" compiles and "function that requires everything a skylake processor has". An intermediate result could be taking a look at the target attribute on the callee and posting that as a "set" of features that are required by the caller without bothering to do the set difference?</div><div><br></div><div> I'll look into doing that, though it might not be immediately.</div><div><br></div><div>Thoughts?</div><div><br></div><div>-eric</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
 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>
+    // 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" target="_blank">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></div></div></blockquote></div></div>