-
Notifications
You must be signed in to change notification settings - Fork 760
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
WIP: [SYCL] Implement SYCL address space attributes handling #968
Conversation
Default address space (applies when no explicit address space was specified) maps to generic (4) address space. Added SYCLDevice environment to triple. Static variables without address space now reside in global address space, unless they have an explicit address space qualifier in source code. Although OpenCL specification explicitly states that a string literal should reside in constant address space, it does not work for SYCL with "generic by default" address space rules. For example: const char *getLiteral() { return "A"; } void func(bool AorB) { char B[] = {'B', '\0'}; const char* C = AorB ? A : B; } If `A' reside in constant address space, it cannot be returned from a function `getLiteral', because it returns a generic const char*. When default address space values in C++ are CodeGen'ed into different address spaces in LLVM IR, we must ensure that an addrspacecast is emitted before a bitcast. Pointers with the same address space in AST may end up in different address spaces in IR. We cannot CodeGen a conditional operator (ternary 'if') whose operands have different address spaces, so we have to addrspacecast them to generic. When a static variable is lowered from AST to LLVM IR, it can change an address space depending on its storage class. For example, a static variable declared in function scope may be assigned to global address space if language rules allow. When this happens, original address space of a variable (retuned by D.getType()) is no longer can be used as target address space. Correct address space for a global can be obtained from CodeGenModule::GetGlobalVarAddressSpace function, but in this case we just copy it from the existing global (OldGV). Pointers with the same address space in AST may end up in different address spaces in IR. We cannot CodeGen a binary compare operator (<, >, ==, etc.) whose operands have different address spaces, so we have to addrspacecast them to generic. Emit address space cast if return type and return value have different address spaces. Invalid bitcast with different address spaces was emitted as arument of llvm.invariant.start intrinsic for work group scope constants. This problem caused assertion fail. Make sure that all operands of phi instruction that is generated while lowering conditional operator have the same type. This fixes compiler assertion. Signed-off-by: Alexey Bader <alexey.bader@intel.com>
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 any objections, just a couple of questions/suggestions.
@asavonic , it would be nice if you take a look.
@@ -2285,7 +2285,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp | |||
if (Context.getASTContext().addressSpaceMapManglingFor(AS)) { | |||
// <target-addrspace> ::= "AS" <address-space-number> | |||
unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS); | |||
if (TargetAS != 0) | |||
if (TargetAS != 0 || (Context.getASTContext().getLangOpts().SYCLIsDevice)) |
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.
Don't you know why we need this 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.
sycl_private
address is mapped to 0
for SPIR as well as default address space, so in order to "specialize" templates with the sycl_private
qualified types, we have to mangle them differently from the unqualified types.
Test case is here: https://github.com/intel/llvm/pull/968/files#diff-4e74dfb66665848ae647af85422c78d8R41
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.
sycl_private address is mapped to 0 for SPIR as well as default address space
Default address space is supposed to be akin to generic, i.e. it should be mapped to 4.
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.
Sorry, my previous reply is not quite accurate.
This change is needed because pointers qualified with address space mapped to 0
LLVM AS are mangled the same way as unquliafied pointers.
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, that makes sense.
However, I'm surprised that we don't have a similar code for OpenCL here. opencl_private
is also mapped to 0, but it has a distinct mangling:
__attribute__((overloadable))
void foo(__private int *ip) {
*ip = 0;
}
// magled as: _Z3fooPU9CLprivatei
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.
We have similar problem for OpenCL targeting SPIR. You seemed to use some other target your example. X86?
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.
Sorry, the problem I'm talking about is mangling, not the mangled names conflict.
Mangled names conflict is not a problem in OpenCL as OpenCL compiler qualifies all the pointers.
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.
We have similar problem for OpenCL targeting SPIR. You seemed to use some other target your example. X86?
Right, sorry for the confusion. With -triple spir
the function is mangled as _Z3fooPi
.
Sorry, the problem I'm talking about is mangling, not the mangled names conflict.
Mangled names conflict is not a problem in OpenCL as OpenCL compiler qualifies all the pointers.
I don't quite understand what the problem is. Can provide a test case?
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 test case is added to this PR already: https://github.com/intel/llvm/pull/968/files#diff-9cbf615457fd73dff7e9840ed855fa9a and problem is covered in this thread. I just clarified why it affects only SYCL compiler, but not OpenCL.
Smaller reproducer:
template<typename T>
void tmpl(T t){}
__attribute__((opencl_private)) int *PRIV;
tmpl(PRIV);
int *NoAS;
tmpl(NoAS);
SYCL compiler produces the same mangled name for two tmpl
instances, OpenCL compiler adds generic
qualifier for NoAS
declaration and produces different names.
Let me know if it's still unclear.
I think original patch from @erichkeane mapped sycl_private
address space to AS 5
. This might be an alternative option, but we need LLVM-SPIRV translator to support alternative mappings as well.
(other.getAddressSpace() == LangAS::sycl_private || | ||
other.getAddressSpace() == LangAS::sycl_local || | ||
other.getAddressSpace() == LangAS::sycl_global || | ||
other.getAddressSpace() == LangAS::sycl_constant)); |
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.
Hmm, maybe it would be good to add a comment explaining why we allowed casting between "empty" address space and others. At least for casts to sycl_constant
address spaces.
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.
@asavonic, can you help with that?
casts to sycl_constant address spaces
I don't think this casts should be allowed as they are not legal in OpenCL env.
Another option would be skipping sycl_constant
in this patch.
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 think this casts should be allowed as they are not legal in OpenCL env.
Agree.
@@ -42,6 +42,12 @@ enum class LangAS : unsigned { | |||
cuda_constant, | |||
cuda_shared, | |||
|
|||
// SYCL specific address spaces. |
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.
Please remind me why we define these SYCL address spaces, and not use the OpenCL 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 experimented in this direction and existing rules for OpenCL address spaces prohibit casts between qualified and unqualified pointers. I can share my patch if you are interested.
If I understand the logic you implemented is semantically different from the OpenCL semantics, but as long as we produce valid SPIR-V module it should be fine.
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.
FYI: current status of experiment with using OpenCL address spaces can be found in my private fork.
__attribute__((opencl_local)) int *LOC; | ||
int *NoAS; | ||
|
||
bar(*GLOB); |
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.
Since bar
takes a private pointer (reference), and *GLOB
is global pointer (reference), we essentially addrspace cast here from global to private. Why this is a positive test case?
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.
If I understand it correctly, there is no invalid casts thanks to this overload:
void bar(int & Data) {}
+@erichkeane to confirm.
Signed-off-by: Alexey Bader <alexey.bader@intel.com>
Signed-off-by: Alexey Bader <alexey.bader@intel.com>
Alternative implementation: #1039. Please, take a look and let me know if you have any concerns regarding OpenCL address space attributes re-use in SYCL mode. |
This approach is abandoned in favor of OpenCL attributes re-use. |
This pull request is created to gather SYCL working group internal feedback before uploading the patch to LLVM phabricator.
Default address space (applies when no explicit address space was
specified) maps to generic (4) address space.
Added SYCLDevice environment to triple.
Static variables without address space now reside in global address
space, unless they have an explicit address space qualifier in source
code.
Although OpenCL specification explicitly states that a string literal
should reside in constant address space, it does not work for SYCL
with "generic by default" address space rules.
For example:
const char *getLiteral() {
return "A";
}
void func(bool AorB) {
char B[] = {'B', '\0'};
const char* C = AorB ? A : B;
}
If
A' reside in constant address space, it cannot be returned from a function
getLiteral', because it returns a generic const char*.When default address space values in C++ are CodeGen'ed into different
address spaces in LLVM IR, we must ensure that an addrspacecast is
emitted before a bitcast.
Pointers with the same address space in AST may end up in different
address spaces in IR. We cannot CodeGen a conditional
operator (ternary 'if') whose operands have different address spaces,
so we have to addrspacecast them to generic.
When a static variable is lowered from AST to LLVM IR, it can change an
address space depending on its storage class. For example, a static
variable declared in function scope may be assigned to global address
space if language rules allow. When this happens, original address space
of a variable (retuned by D.getType()) is no longer can be used as
target address space. Correct address space for a global can be obtained
from CodeGenModule::GetGlobalVarAddressSpace function, but in this case
we just copy it from the existing global (OldGV).
Pointers with the same address space in AST may end up in different
address spaces in IR. We cannot CodeGen a binary compare
operator (<, >, ==, etc.) whose operands have different address spaces,
so we have to addrspacecast them to generic.
Emit address space cast if return type and return value have different
address spaces.
Invalid bitcast with different address spaces was emitted as arument of
llvm.invariant.start intrinsic for work group scope constants.
This problem caused assertion fail.
Make sure that all operands of phi instruction that is generated while
lowering conditional operator have the same type. This fixes compiler
assertion.