Skip to content

Commit

Permalink
[CodeGen] Improve diagnostics related to target attributes
Browse files Browse the repository at this point in the history
Summary:
When requirement imposed by __target__ attributes on functions
are not satisfied, prefer printing those requirements, which
are explicitly mentioned in the attributes.

This makes such messages more useful, e.g. printing avx512f instead of avx2
in the following scenario:

```
$ cat foo.c
static inline void __attribute__((__always_inline__, __target__("avx512f")))
x(void)
{
}

int main(void)
{
            x();
}
$ clang foo.c
foo.c:7:2: error: always_inline function 'x' requires target feature 'avx2', but would be inlined into function 'main' that is compiled without support for 'avx2'
        x();
    ^
1 error generated.
```

bugzilla: https://bugs.llvm.org/show_bug.cgi?id=37338

Reviewers: craig.topper, echristo, dblaikie

Reviewed By: craig.topper, echristo

Differential Revision: https://reviews.llvm.org/D46541



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@334174 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
GBuella committed Jun 7, 2018
1 parent 9185154 commit c307b50
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 26 deletions.
10 changes: 10 additions & 0 deletions lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2330,9 +2330,19 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E,

} else if (TargetDecl->hasAttr<TargetAttr>()) {
// Get the required features for the callee.

const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
TargetAttr::ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD);

SmallVector<StringRef, 1> ReqFeatures;
llvm::StringMap<bool> CalleeFeatureMap;
CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);

for (const auto &F : ParsedAttr.Features) {
if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1)))
ReqFeatures.push_back(StringRef(F).substr(1));
}

for (const auto &F : CalleeFeatureMap) {
// Only positive features are "required".
if (F.getValue())
Expand Down
26 changes: 16 additions & 10 deletions lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5033,22 +5033,28 @@ void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
}
}

TargetAttr::ParsedTargetAttr CodeGenModule::filterFunctionTargetAttrs(const TargetAttr *TD) {
assert(TD != nullptr);
TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();

ParsedAttr.Features.erase(
llvm::remove_if(ParsedAttr.Features,
[&](const std::string &Feat) {
return !Target.isValidFeatureName(
StringRef{Feat}.substr(1));
}),
ParsedAttr.Features.end());
return ParsedAttr;
}


// Fills in the supplied string map with the set of target features for the
// passed in function.
void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
const FunctionDecl *FD) {
StringRef TargetCPU = Target.getTargetOpts().CPU;
if (const auto *TD = FD->getAttr<TargetAttr>()) {
// If we have a TargetAttr build up the feature map based on that.
TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();

ParsedAttr.Features.erase(
llvm::remove_if(ParsedAttr.Features,
[&](const std::string &Feat) {
return !Target.isValidFeatureName(
StringRef{Feat}.substr(1));
}),
ParsedAttr.Features.end());
TargetAttr::ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD);

// Make a copy of the features as passed on the command line into the
// beginning of the additional features from the function to override.
Expand Down
4 changes: 4 additions & 0 deletions lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,10 @@ class CodeGenModule : public CodeGenTypeCache {
/// It's up to you to ensure that this is safe.
void AddDefaultFnAttrs(llvm::Function &F);

/// Parses the target attributes passed in, and returns only the ones that are
/// valid feature names.
TargetAttr::ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD);

// Fills in the supplied string map with the set of target features for the
// passed in function.
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Expand Down
36 changes: 22 additions & 14 deletions test/CodeGen/target-features-error-2.c
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_SSE42
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_1
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_2
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_3
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_4
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX512f
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -target-feature +movdir64b -S -verify -o - -D NEED_MOVDIRI
// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -target-feature +avx512vnni -target-feature +movdiri -S -verify -o - -D NEED_CLWB

#define __MM_MALLOC_H
#include <x86intrin.h>

#if NEED_SSE42
#if NEED_AVX_1
int baz(__m256i a) {
return _mm256_extract_epi32(a, 3); // expected-error {{'__builtin_ia32_vec_ext_v8si' needs target feature avx}}
}
#endif

#if NEED_AVX_1
#if NEED_AVX_2
__m128 need_avx(__m128 a, __m128 b) {
return _mm_cmp_ps(a, b, 0); // expected-error {{'__builtin_ia32_cmpps' needs target feature avx}}
}
#endif

#if NEED_AVX_2
__m128 need_avx(__m128 a, __m128 b) {
return _mm_cmp_ss(a, b, 0); // expected-error {{'__builtin_ia32_cmpss' needs target feature avx}}
#if NEED_AVX512f
unsigned short need_avx512f(unsigned short a, unsigned short b) {
return __builtin_ia32_korhi(a, b); // expected-error {{'__builtin_ia32_korhi' needs target feature avx512f}}
}
#endif

#if NEED_AVX_3
__m128d need_avx(__m128d a, __m128d b) {
return _mm_cmp_pd(a, b, 0); // expected-error {{'__builtin_ia32_cmppd' needs target feature avx}}
#if NEED_MOVDIRI
void need_movdiri(unsigned int *a, unsigned int b) {
__builtin_ia32_directstore_u32(a, b); // expected-error {{'__builtin_ia32_directstore_u32' needs target feature movdiri}}
}
#endif

#if NEED_AVX_4
__m128d need_avx(__m128d a, __m128d b) {
return _mm_cmp_sd(a, b, 0); // expected-error {{'__builtin_ia32_cmpsd' needs target feature avx}}
#if NEED_CLWB
static __inline__ void
__attribute__((__always_inline__, __nodebug__, __target__("avx512vnni,clwb,movdiri,movdir64b")))
func(unsigned int *a, unsigned int b)
{
__builtin_ia32_directstore_u32(a, b);
}

void need_clwb(unsigned int *a, unsigned int b) {
func(a, b); // expected-error {{always_inline function 'func' requires target feature 'clwb', but would be inlined into function 'need_clwb' that is compiled without support for 'clwb'}}

}
#endif
3 changes: 1 addition & 2 deletions test/CodeGen/target-features-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ int __attribute__((target("avx"), always_inline)) foo(int a) {
return a + 4;
}
int bar() {
return foo(4); // expected-error {{always_inline function 'foo' requires target feature 'sse4.2', but would be inlined into function 'bar' that is compiled without support for 'sse4.2'}}
return foo(4); // expected-error {{always_inline function 'foo' requires target feature 'avx', but would be inlined into function 'bar' that is compiled without support for 'avx'}}
}

0 comments on commit c307b50

Please sign in to comment.