Skip to content
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

Closed
wants to merge 3 commits into from

Conversation

bader
Copy link
Contributor

@bader bader commented Dec 24, 2019

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.

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>
@bader bader added the upstream This change is related to upstreaming SYCL support to llorg. label Dec 24, 2019
@bader bader self-assigned this Dec 24, 2019
Copy link
Contributor

@Fznamznon Fznamznon left a 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))
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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));
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

bader added 2 commits January 18, 2020 14:48
Signed-off-by: Alexey Bader <alexey.bader@intel.com>
Signed-off-by: Alexey Bader <alexey.bader@intel.com>
@bader
Copy link
Contributor Author

bader commented Jan 22, 2020

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.
Once we finalize the approach, I'll update the patch for upstream to llvm.org.

@bader bader changed the title [SYCL] Implement SYCL address space attributes handling WIP: [SYCL] Implement SYCL address space attributes handling Jan 22, 2020
@bader
Copy link
Contributor Author

bader commented Apr 25, 2020

This approach is abandoned in favor of OpenCL attributes re-use.
See #1581.

@bader bader closed this Apr 25, 2020
@bader bader deleted the sycl-address-space branch April 25, 2020 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
upstream This change is related to upstreaming SYCL support to llorg.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants