-
Notifications
You must be signed in to change notification settings - Fork 787
[SYCL][ESIMD] Support SYCL accessors in ESIMD mode in the FE. #1755
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
Conversation
Options name: -fsycl-explicit-simd. This option is temporary until ESIMD and normal SYCL kernels can co-exist in the same source. Signed-off-by: Konstantin S Bobrovsky <[email protected]>
FE detects whether an accessor kernel parameter is an accessor passed to a ESIMD kernel), and marks the corrsponding integration header parameter descriptor accordingly. Signed-off-by: Konstantin S Bobrovsky <[email protected]>
// Cooperate with the SYCL API, which defines this method iff the accessor is | ||
// ESIMD accessor. | ||
assert(Util::isSyclAccessorType(AccTy) && "sycl::accessor expected"); | ||
return getMethodByName(AccTy, "ESIMDBufferAccessorMarker") != nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get why we have to distinguish ESIMD accessors from default ones if user cannot specify that accessor is ESIMD accessor and it is not possible to get a program with ESIMD and default accessors at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There will be corresponding runtime patch, which makes it clear why, + provides more detailed comments.
In short, for accessors in ESIMD kernels memory object creation is different - it is not clCreateBuffer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, in this case there could be difference in process of setting kernel arguments, that is why you need to change descriptor in the integration header.
But I still don't get this searching for internal method. Why we don't threat all accessors as ESIMD ones when ESIMD extension is enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because some day we want to mix SIMD and normal kernels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit concerned about having additional handling for ESIMD accessors. I think, we were moving to unification of kernel arguments handling. This stuff just breaks this direction. Is it possible to elaborate what is the difference in RT handling between SIMD accessors and default ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I explained above:
In short, for accessors in ESIMD kernels memory object creation is different - it is not clCreateBuffer
that's the only difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CUDA and L0 back-ends doesn't use clCreateBuffer
to allocate the memory and still they don't require special accessors. I don't follow why ESIMD kernels memory object creation requires compiler changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CUDA and L0 back-ends doesn't use clCreateBuffer to allocate the memory and still they don't require special accessors. I don't follow why ESIMD kernels memory object creation requires compiler changes.
This is a good example, which can help clarify.
CUDA and L0 are separate back-ends, as you correctly mentioned. What I need here is to distinguish usual accessors and ESIMD accessors within the same backend - be it L0 or OpenCL. I see that L0 is finally integrated into open-source, and I'll need to adjust the changes, but their sense will be the same - different sequence of PI calls will be needed to create memory object for the ESIMD accessor.
I could tag a kernel with "I am SIMD kernel" info, then diverge accessor handling based on that. But my estimation was that that would be much more intrusive and unsafe change to the runtime. I can add a TODO naming this alternative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I explained my concerns above. We were moving to unification of kernel arguments generation, so we can improve detection and handling of special SYCL types (i.e. accessors, sampler and streams) by using an attribute. This approach was discussed during upstreaming WG meeting and we agreed that it is better than what we have now. Adding new accessor type doesn't seem like the change compatible with this direction, so I would prefer tagging kernels. Although I don't have enough expertise in RT to evaluate how intrusive and unsafe change to the runtime. @bader, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The splitting of the isSyclType and matchQualifiedTypeName is odd, and likely unnecessary. Can you explain your motivation for doing that?
@@ -20,6 +20,8 @@ | |||
using namespace clang; | |||
using namespace CodeGen; | |||
|
|||
namespace { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get the purpose here, but this seems to be an unrelated change. Please submit it as a separate aptch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem of absent anonymous namespace (and exported symbol names clash) is triggered by this patch. Separate patch would make it hard to understand the real purpose.
Besides, all patches that I've already submitted are ~5% of the overall line count of the feature. I simply can't split all tiny unrelated changes into separate patches given the time I have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The schedule of your feature doesn't alter our code review guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not asking to change code review guidelines, I'm providing context. Guidelines are quite flexible, and they are just guidelines. There maybe other factors like business needs.
In this particular case, you probably missed the first part of my reasoning:
The problem of absent anonymous namespace (and exported symbol names clash) is triggered by this patch. Separate patch would make it hard to understand the real purpose.
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not miss that.
@@ -54,6 +54,8 @@ enum KernelInvocationKind { | |||
const static std::string InitMethodName = "__init"; | |||
const static std::string FinalizeMethodName = "__finalize"; | |||
|
|||
namespace { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replied above
@@ -62,6 +64,7 @@ class Util { | |||
/// Checks whether given clang type is a full specialization of the SYCL | |||
/// accessor class. | |||
static bool isSyclAccessorType(const QualType &Ty); | |||
static bool isSyclAccessorType(const CXXRecordDecl *RecTy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these overloads necessary? Is it not possible to just make the uses do RecordDecl->getType()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is another interface for convenience. Plus this avoids unnecessary dereferences, dyn_cast and branch:
bool Util::isSyclAccessorType(const QualType &Ty) {
if (const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl())
return isSyclAccessorType(RecTy);
return false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd prefer just having people write ->getType instead of this. You end up repeating all the record-decl detection code 1/2 dozen times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is matter of taste. If you insist I can change - ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think your change reduces readability, and is otherwise an unrelated change. @Fznamznon , thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have strong preference regarding this, but for me it seems that there become a bit more code than it was before, so I don't mind reverting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Fznamznon, do you mind leaving it as is?
clang/lib/Sema/SemaSYCL.cpp
Outdated
@@ -2017,7 +2041,13 @@ SYCLIntegrationHeader::SYCLIntegrationHeader(DiagnosticsEngine &_Diag, | |||
// ----------------------------------------------------------------------------- | |||
|
|||
bool Util::isSyclAccessorType(const QualType &Ty) { | |||
return isSyclType(Ty, "accessor", true /*Tmpl*/); | |||
if (const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems odd here. Why can't isSyclType handle this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
between isSyclType and matchQualifiedTypeName there is a lot of boilerplate code, whose duplication is avoided by this splitting, thus improving maintainability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave it to @Fznamznon to comment on the split of this but I'm concerned that we have two types of accessors that are so close to eachother. I cannot fathom why we cannot unify the handling of these two types better, so I'll leave it to her to close with.
@@ -20,6 +20,8 @@ | |||
using namespace clang; | |||
using namespace CodeGen; | |||
|
|||
namespace { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still this.
@@ -62,6 +64,7 @@ class Util { | |||
/// Checks whether given clang type is a full specialization of the SYCL | |||
/// accessor class. | |||
static bool isSyclAccessorType(const QualType &Ty); | |||
static bool isSyclAccessorType(const CXXRecordDecl *RecTy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd prefer just having people write ->getType instead of this. You end up repeating all the record-decl detection code 1/2 dozen times.
@kbobrovs, could you elaborate in the description what problem this patch is trying to resolve? |
I provided a short description in the intro for this PR:
This is the essence. Runtime creates different memory object so that explicit SIMD APIs work on SYCL accessors. The FE part if enabling the upcoming changes in runtime where all details should be clear. |
} | ||
|
||
bool Util::matchQualifiedTypeName(const QualType &Ty, | ||
ArrayRef<Util::DeclContextDesc> Scopes) { | ||
if (const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this 3 line pattern everywhere, make this whole body be:
return matchQualifiedTypeName(Ty->getAsCXXRecordDecl(), Scopes);
Then, in matchQualifiedType name, leave the
if (!RecTy) return false;
part.
Will implement temporary runtime-only solution instead. |
REVIEW ONLY THE LAST COMMIT
FE detects whether an accessor kernel parameter is an accessor
passed to a ESIMD kernel), and marks the corrsponding integration
header parameter descriptor accordingly.
ESIMD accessors are handled differently at runtime (image1d_buffer_t is created).
Accompanying runtime changes are coming later.
Signed-off-by: Konstantin S Bobrovsky [email protected]