-
Notifications
You must be signed in to change notification settings - Fork 779
[SYCL] Add SYCLPropagateAspectUsage Pass #5348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a94f4e3
58479f6
59c12ed
bfadc0b
40eb790
471814e
1973f1b
02ff770
427c18d
be7e7f2
1daf094
8163a0e
5c14699
da7d34a
79147ac
83e3e5b
931bb7b
fe05491
cd81ba9
8998d89
6214a10
65b7d80
5f274b8
824f9df
5ad3b08
b6e9526
b6eafb1
eef814a
76f6864
e7b7728
d122167
e4fa2cc
d6b1c3f
483ed82
c11e71d
02225b3
cdf83fe
3bbc3c2
495e006
4495e00
a3c4d28
9ffe87a
e3fda46
7f125d5
28a3753
8ed6c15
a4c5443
a963dac
ab6eeb2
70bf013
9be4c55
e9f03d7
842247d
13745b9
e28f61a
307fe3d
38d2041
c5fa2de
b491190
cf668e9
bf7134a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -444,6 +444,7 @@ namespace clang { | |
void OptimizationFailureHandler( | ||
const llvm::DiagnosticInfoOptimizationFailure &D); | ||
void DontCallDiagHandler(const DiagnosticInfoDontCall &D); | ||
void SYCLWarningDiagHandler(const DiagnosticInfoSYCLUnspecAspect &D); | ||
}; | ||
|
||
void BackendConsumer::anchor() {} | ||
|
@@ -825,6 +826,27 @@ void BackendConsumer::DontCallDiagHandler(const DiagnosticInfoDontCall &D) { | |
<< llvm::demangle(D.getFunctionName().str()) << D.getNote(); | ||
} | ||
|
||
void BackendConsumer::SYCLWarningDiagHandler( | ||
const DiagnosticInfoSYCLUnspecAspect &D) { | ||
// FIXME: instead of querying source location from debug info, we should | ||
// re-use existing mechanism with srcloc metadata, see D106030, D110364. | ||
SourceLocation Loc; | ||
Diags.Report(Loc, diag::warn_sycl_wrong_aspect_usage) | ||
Comment on lines
+833
to
+834
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, it uses invalid source location, so the warning won't point to real code. Maybe we can try to construct valid source info at least when we have debug info? Seems like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good idea and it seems like that is a better approach than we have right now. However, Amount of the changes in this PR is already huge, would it be acceptable to postpone this diagnostic improvement till the next PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it is ok to postpone. Please file a tracker if you're not going to work on it ASAP. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm less certain it's okay to postpone as this means all diagnostics will show up in very wrong places (if at all) within an IDE, for example. I don't think the user experience is all that great when the diagnostic is a warning that's divorced from their code. Note: losing source location information and providing a poor user experience with diagnostics is why very few diagnostics ever come from the backend. It's too easy to lose the source locations, especially when optimizer passes get involved. That's why the majority of backend diagnostics are in the form of remarks instead of warnings (let alone errors). We should be very careful about the user experience here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Note that we are in the very beginning of our optional kernel features implementation journey and even if user properly sets all the attributes, the code won't work as expected, because we are missing a lot of changes in other components. Therefore, I think that it should be ok not to complicate this PR even more, but still refactor diagnostics before we mark the whole feature as completed.
That pass is supposed to be launched before all other passes or otherwise not only source locations will be lost, but also some semantics, i.e. we can lose information about declared aspects due to inlining. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm ok with this approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've created #5877 to track this further improvement |
||
<< D.getFunctionName() << D.getAspect(); | ||
|
||
if (!D.getCallChain().empty()) { | ||
Diags.Report(Loc, diag::note_sycl_wrong_aspect_usage) | ||
<< /* the actual use */ 0 << D.getCallChain().back() | ||
<< !D.isFullDebugMode(); | ||
|
||
for (auto I = ++D.getCallChain().rbegin(), E = D.getCallChain().rend(); | ||
I != E; ++I) { | ||
Diags.Report(Loc, diag::note_sycl_wrong_aspect_usage) | ||
Comment on lines
+838
to
+844
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't both of these notes be on a location from the call chain instead of using the invalid source location? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, do I understand it correctly that this will also be applied in the next PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, properly dealing with source location requires more changes and I would prefer not to overcomplicate this PR anymore, I've submitted #5877 to track this further improvement |
||
<< /* called by */ 1 << *I << !D.isFullDebugMode(); | ||
} | ||
} | ||
} | ||
|
||
/// This function is invoked when the backend needs | ||
/// to report something to the user. | ||
void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { | ||
|
@@ -899,6 +921,9 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { | |
case llvm::DK_DontCall: | ||
DontCallDiagHandler(cast<DiagnosticInfoDontCall>(DI)); | ||
return; | ||
case llvm::DK_SYCLWarning: | ||
SYCLWarningDiagHandler(cast<DiagnosticInfoSYCLUnspecAspect>(DI)); | ||
return; | ||
default: | ||
// Plugin IDs are not bound to any value as they are set dynamically. | ||
ComputeDiagRemarkID(Severity, backend_plugin, DiagID); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Checks that Propagate aspect usage Pass is run for SYCL device target. | ||
// | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown %s -flegacy-pass-manager -mllvm -debug-pass=Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-SYCL1 | ||
// CHECK-SYCL1: Propagate aspect usage | ||
// | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown %s -flegacy-pass-manager -fno-sycl-early-optimizations -mllvm -debug-pass=Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-SYCL2 | ||
// CHECK-SYCL2: Propagate aspect usage | ||
// | ||
// RUN: %clang_cc1 %s -flegacy-pass-manager -mllvm -debug-pass=Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-SYCL1 | ||
// CHECK-NOT-SYCL1-NOT: Propagate aspect usage | ||
// | ||
// | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown %s -fno-legacy-pass-manager -mdebug-pass Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-NEWPM-SYCL1 | ||
// CHECK-NEWPM-SYCL1: PropagateAspectUsagePass | ||
// | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown %s -fno-legacy-pass-manager -fno-sycl-early-optimizations -mdebug-pass Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-NEWPM-SYCL2 | ||
// CHECK-NEWPM-SYCL2: PropagateAspectUsagePass | ||
// | ||
// RUN: %clang_cc1 %s -fno-legacy-pass-manager -mdebug-pass Structure -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-NEWPM-NOT-SYCL | ||
// CHECK-NEWPM-NOT-SYCL-NOT: PropagateAspectUsagePass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#pragma once | ||
|
||
#define ATTR_SYCL_KERNEL __attribute__((sycl_kernel)) | ||
|
||
inline namespace cl { | ||
namespace sycl { | ||
|
||
// Dummy aspect enum with limited enumerators | ||
enum class aspect { | ||
host = 0, | ||
cpu = 1, | ||
gpu = 2, | ||
accelerator = 3, | ||
custom = 4, | ||
fp16 = 5, | ||
fp64 = 6, | ||
}; | ||
|
||
class kernel {}; | ||
class context {}; | ||
class device {}; | ||
class event {}; | ||
|
||
class queue { | ||
public: | ||
template <typename T> | ||
event submit(T cgf) { return event{}; } | ||
|
||
void wait() {} | ||
void wait_and_throw() {} | ||
void throw_asynchronous() {} | ||
}; | ||
|
||
class auto_name {}; | ||
template <typename Name, typename Type> | ||
struct get_kernel_name_t { | ||
using name = Name; | ||
}; | ||
template <typename Type> | ||
struct get_kernel_name_t<auto_name, Type> { | ||
using name = Type; | ||
}; | ||
|
||
class kernel_handler { | ||
void __init_specialization_constants_buffer(char *specialization_constants_buffer) {} | ||
}; | ||
|
||
#define ATTR_SYCL_KERNEL __attribute__((sycl_kernel)) | ||
template <typename KernelName, typename KernelType> | ||
ATTR_SYCL_KERNEL void kernel_single_task(const KernelType &kernelFunc) { // #KernelSingleTask | ||
kernelFunc(); | ||
} | ||
|
||
class handler { | ||
public: | ||
template <typename KernelName = auto_name, typename KernelType> | ||
void single_task(const KernelType &kernelFunc) { | ||
using NameT = typename get_kernel_name_t<KernelName, KernelType>::name; | ||
#ifdef __SYCL_DEVICE_ONLY__ | ||
kernel_single_task<NameT>(kernelFunc); | ||
#else | ||
kernelFunc(); | ||
#endif | ||
} | ||
}; | ||
|
||
} // namespace sycl | ||
} // namespace cl |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Test checks Propagate Aspect Usage pass. | ||
|
||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-WARNINGS | ||
elizabethandrews marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown %s -debug-info-kind=constructor -dwarf-version=5 -emit-llvm -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-WARNINGS-DBG -DPATH=%s | ||
|
||
// CHECK-WARNINGS: warning: function 'checkStructUsesAspect(int)' uses aspect 'fp16' not listed in 'sycl::device_has()' | ||
// CHECK-WARNINGS-NEXT: note: the actual use is in funcWithStruct(int), compile with '-g' to get source location | ||
// CHECK-WARNINGS-NEXT: note: which is called by checkStructUsesAspect(int), compile with '-g' to get source location | ||
// | ||
// CHECK-WARNINGS-DBG: warning: function 'checkStructUsesAspect(int)' uses aspect 'fp16' not listed in 'sycl::device_has()' | ||
// CHECK-WARNINGS-DBG-NEXT: note: the actual use is in funcWithStruct(int) at [[PATH]]:27:5 | ||
// CHECK-WARNINGS-DBG-NEXT: note: which is called by checkStructUsesAspect(int) at [[PATH]]:32:10 | ||
|
||
#include "Inputs/sycl.hpp" | ||
|
||
using namespace cl::sycl; | ||
|
||
class KernelName; | ||
|
||
struct [[__sycl_detail__::__uses_aspects__(aspect::fp16)]] Struct { | ||
elizabethandrews marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int a = 0; | ||
}; | ||
|
||
int funcWithStruct(int) { | ||
Struct s; | ||
s.a = 1; | ||
return s.a; | ||
} | ||
|
||
[[sycl::device_has(aspect::fp64)]] int checkStructUsesAspect(int) { | ||
return funcWithStruct(1); | ||
} | ||
|
||
// Check that empty device_has() emits a warning. | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-EMPTY | ||
// CHECK-EMPTY: warning: function 'checkEmptyDeviceHas()' uses aspect 'fp16' not listed in 'sycl::device_has()' | ||
[[sycl::device_has()]] int checkEmptyDeviceHas() { | ||
return funcWithStruct(1); | ||
} | ||
|
||
[[sycl::device_has(aspect::fp16)]] int func2() { | ||
return funcWithStruct(1); | ||
} | ||
|
||
// Check that empty device_has() emits a warning despite the fact | ||
// that invoked function's device_has() attribute is conformant | ||
// with actual usage. | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-EMPTY2 | ||
// CHECK-EMPTY2: warning: function 'checkEmptyDeviceHas()' uses aspect 'fp16' not listed in 'sycl::device_has()' | ||
[[sycl::device_has()]] int checkEmptyDeviceHas2() { | ||
return func2(); | ||
} | ||
|
||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-DOUBLE | ||
// CHECK-DOUBLE: warning: function 'checkDouble()' uses aspect 'fp64' not listed in 'sycl::device_has()' | ||
// CHECK-DOUBLE-NEXT: note: the actual use is in checkDouble(), compile with '-g' to get source location | ||
|
||
[[sycl::device_has(aspect::fp16)]] int checkDouble() { | ||
double d = 123; | ||
// Strange calculations just to prevent AST optimizations | ||
for (int i = 0; i < 10; ++i) | ||
d += d * d; | ||
|
||
return d; | ||
} | ||
|
||
struct [[__sycl_detail__::__uses_aspects__(aspect::cpu)]] StructWithCpu { | ||
int a = 0; | ||
}; | ||
|
||
int funcWithSeveralAspects() { | ||
Struct s1; | ||
StructWithCpu s2; | ||
return static_cast<double>(s1.a); | ||
} | ||
|
||
// Check that a warning diagnostic works in a case | ||
elizabethandrews marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// when there are several aspects present which conflict | ||
// with declared in device_has(). | ||
|
||
// Check for fp64 aspect | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-SEVERAL-FP64 | ||
elizabethandrews marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// CHECK-SEVERAL-FP64: warning: function 'checkSeveralAspects()' uses aspect 'fp64' not listed in 'sycl::device_has()' | ||
// CHECK-SEVERAL-FP64-NEXT: note: the actual use is in funcWithSeveralAspects(), compile with '-g' to get source location | ||
// CHECK-SEVERAL-FP64-NEXT: note: which is called by checkSeveralAspects(), compile with '-g' to get source location | ||
// | ||
// Check for cpu aspect | ||
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix CHECK-SEVERAL-CPU | ||
// CHECK-SEVERAL-CPU: warning: function 'checkSeveralAspects()' uses aspect 'cpu' not listed in 'sycl::device_has()' | ||
// CHECK-SEVERAL-CPU-NEXT: note: the actual use is in funcWithSeveralAspects(), compile with '-g' to get source location | ||
// CHECK-SEVERAL-CPU-NEXT: note: which is called by checkSeveralAspects(), compile with '-g' to get source location | ||
[[sycl::device_has(aspect::fp16)]] int checkSeveralAspects() { | ||
return funcWithSeveralAspects(); | ||
} | ||
|
||
int main() { | ||
queue Q; | ||
Q.submit([&](handler &h) { | ||
h.single_task<KernelName>([=]() { | ||
checkStructUsesAspect(1); | ||
checkEmptyDeviceHas(); | ||
checkDouble(); | ||
checkSeveralAspects(); | ||
}); | ||
}); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.