Skip to content

[OpenCL] Put constant initializer globals into constant addrspace #90048

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

Merged
merged 4 commits into from
May 2, 2024

Conversation

svenvh
Copy link
Member

@svenvh svenvh commented Apr 25, 2024

Place constant initializer globals into the constant address space. Clang generates such globals for e.g. larger array member initializers of classes and then emits copy operations from the global to the object(s). The globals are never written so they ought to be in the constant address space.

Place constant initializer globals into the constant address space.
Clang generates such globals for e.g. larger array member initializers
of classes and then emits copy operations from the global to the
object(s).  The globals are never written so they ought to be in the
constant address space.
@svenvh svenvh added the OpenCL label Apr 25, 2024
@svenvh svenvh requested a review from AnastasiaStulova April 25, 2024 13:14
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Apr 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 25, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Sven van Haastregt (svenvh)

Changes

Place constant initializer globals into the constant address space. Clang generates such globals for e.g. larger array member initializers of classes and then emits copy operations from the global to the object(s). The globals are never written so they ought to be in the constant address space.


Full diff: https://github.com/llvm/llvm-project/pull/90048.diff

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGExprAgg.cpp (+2)
  • (modified) clang/test/CodeGenOpenCLCXX/addrspace-with-class.clcpp (+4-1)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 355fec42be4489..30cde245cc837c 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -536,6 +536,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
     CodeGen::CodeGenModule &CGM = CGF.CGM;
     ConstantEmitter Emitter(CGF);
     LangAS AS = ArrayQTy.getAddressSpace();
+    if (CGF.getLangOpts().OpenCL)
+      AS = LangAS::opencl_constant;
     if (llvm::Constant *C =
             Emitter.tryEmitForInitializer(ExprToVisit, AS, ArrayQTy)) {
       auto GV = new llvm::GlobalVariable(
diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-with-class.clcpp b/clang/test/CodeGenOpenCLCXX/addrspace-with-class.clcpp
index 18d97a989a4364..a0ed03b25535c8 100644
--- a/clang/test/CodeGenOpenCLCXX/addrspace-with-class.clcpp
+++ b/clang/test/CodeGenOpenCLCXX/addrspace-with-class.clcpp
@@ -5,7 +5,7 @@
 // for constructors, member functions and destructors.
 // See also atexit.cl and global_init.cl for other specific tests.
 
-// CHECK: %struct.MyType = type { i32 }
+// CHECK: %struct.MyType = type { i32, [5 x i32] }
 struct MyType {
   MyType(int i) : i(i) {}
   MyType(int i) __constant : i(i) {}
@@ -14,6 +14,7 @@ struct MyType {
   int bar() { return i + 2; }
   int bar() __constant { return i + 1; }
   int i;
+  int a[5] = {42, 43, 44, 45, 46};
 };
 
 // CHECK: @const1 ={{.*}} addrspace(2) global %struct.MyType zeroinitializer
@@ -23,6 +24,8 @@ __constant MyType const2(2);
 // CHECK: @glob ={{.*}} addrspace(1) global %struct.MyType zeroinitializer
 MyType glob(1);
 
+// CHECK: @constinit ={{.*}} addrspace(2) constant [5 x i32] [i32 42, i32 43, i32 44, i32 45, i32 46]
+
 // CHECK: call spir_func void @_ZNU3AS26MyTypeC1Ei(ptr addrspace(2) {{[^,]*}} @const1, i32 noundef 1)
 // CHECK: call spir_func void @_ZNU3AS26MyTypeC1Ei(ptr addrspace(2) {{[^,]*}} @const2, i32 noundef 2)
 // CHECK: call spir_func void @_ZNU3AS46MyTypeC1Ei(ptr addrspace(4) {{[^,]*}} addrspacecast (ptr addrspace(1) @glob to ptr addrspace(4)), i32 noundef 1)

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@svenvh svenvh merged commit b6328db into llvm:main May 2, 2024
@svenvh svenvh deleted the constinit-constant-addrspace branch May 2, 2024 09:46
@@ -535,20 +535,23 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
elementType.isTriviallyCopyableType(CGF.getContext())) {
CodeGen::CodeGenModule &CGM = CGF.CGM;
ConstantEmitter Emitter(CGF);
LangAS AS = ArrayQTy.getAddressSpace();
QualType GVArrayQTy = CGM.getContext().getAddrSpaceQualType(
CGM.getContext().removeAddrSpaceQualType(ArrayQTy),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We saw a regression caused by this PR. It is a soft hang in CGM.getContext().removeAddrSpaceQualType.
Specifically it is in the following while loop:
while (T.hasAddressSpace()) {
TypeNode = Quals.strip(T);

// If the type no longer has an address space after stripping qualifiers,
// jump out.
if (!QualType(TypeNode, 0).hasAddressSpace())
  break;

// There might be sugar in the way. Strip it and try again.
T = T.getSingleStepDesugaredType(*this);

}
We found that "T == T.getSingleStepDesugaredType(*this);" and this it could not proceed.

I am not sure whether we should break out this loop when "T == T.getSingleStepDesugaredType(*this)"
or something else is wrong that we should never see such case.

Here is the dump of T:
ConstantArrayType 0x555565b40640 '__private ulong[16]' 16
-QualType 0x555565b403f8 '__private ulong' __private -ElaboratedType 0x555565b3ff40 'ulong' sugar imported
-TypedefType 0x555565b3fef0 'ulong' sugar imported |-Typedef 0x555565b3fe80 'ulong' -BuiltinType 0x55556583f430 'unsigned long'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a bug in removeAddrSpaceQualType(): it needs to special-case arrays. Arrays are weird because qualifiers on the element type also count as qualifiers on the type, so getSingleStepDesugaredType() can't remove the sugar on arrays. So it needs to strip the qualifier off the element type, then reconstruct the array type. Maybe it can use ASTContext::getUnqualifiedArrayType.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@changpeng would you be able to provide an input source that demonstrates the issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a bug in removeAddrSpaceQualType(): it needs to special-case arrays. Arrays are weird because qualifiers on the element type also count as qualifiers on the type, so getSingleStepDesugaredType() can't remove the sugar on arrays. So it needs to strip the qualifier off the element type, then reconstruct the array type. Maybe it can use ASTC
getSingleStepDesugaredType
Yes, the issue is in removeAddrSpaceQualType(ArrayQTy), And getSingleStepDesugaredType can not remove "Sugar".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@changpeng would you be able to provide an input source that demonstrates the issue?

Hi, @svenvh : I attached test.cl.txt here which is the dumped opencl source file. Unfortunately I do not know exactly how to reproduce the infinite loop offline with this source. I extracted out the following simplified kernel which can reproduce the hang with

clang -c -Xclang -emit-llvm -O0 test.clcpp

__kernel void nonceGrind(__global ulong *headerIn, __global ulong *nonceOut) {
ulong m[16] = { headerIn[0], headerIn[1],
headerIn[2], headerIn[3],
0, headerIn[5],
headerIn[6], headerIn[7],
headerIn[8], headerIn[9], 0, 0, 0, 0, 0, 0 };
*nonceOut = m[4];
}

However, I am afraid it may not fully represent the original issue. This is because after I break out the loop in
ASTContext::removeAddrSpaceQualType, I am seeing the following assert:

clang: /home/chfang/llvm-project/clang/include/clang/AST/Type.h:677: void clang::Qualifiers::addConsistentQualifiers(Qualifiers): Assertion `getAddressSpace() == qs.getAddressSpace() || !hasAddressSpace() || !qs.hasAddressSpace()' failed.

Hopefully the information is useful, and you are able to help. Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduced further:

clang -c -Xclang -emit-llvm -O0 test.clcpp

__kernel void test(__global ulong *In, __global ulong *Out) {
ulong m[4] = { In[0], In[1], 0, 0 };
*Out = m[1];
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a bug in removeAddrSpaceQualType(): it needs to special-case arrays. Arrays are weird because qualifiers on the element type also count as qualifiers on the type, so getSingleStepDesugaredType() can't remove the sugar on arrays. So it needs to strip the qualifier off the element type, then reconstruct the array type. Maybe it can use ASTContext::getUnqualifiedArrayType.

Thanks for the suggestion. I drafted a fix:
#92612

@changpeng
Copy link
Contributor

test.cl.txt

changpeng added a commit to changpeng/llvm-project that referenced this pull request May 17, 2024
 In building AddrSpaceQualType (llvm#90048),
there is a bug in removeAddrSpaceQualType() for arrays. Arrays are weird because
qualifiers on the element type also count as qualifiers on the type, so
getSingleStepDesugaredType() can't remove the sugar on arrays. This results
in an infinite loop in removeAddrSpaceQualType. To fix the issue,
we use ASTContext::getUnqualifiedArrayType, which strips the qualifier off
the element type, then reconstruct the array type.
changpeng added a commit that referenced this pull request May 20, 2024
In building AddrSpaceQualType
(#90048), there is a bug in
removeAddrSpaceQualType() for arrays. Arrays are weird because
qualifiers on the element type also count as qualifiers on the type, so
getSingleStepDesugaredType() can't remove the sugar on arrays. This
results in an infinite loop in removeAddrSpaceQualType. To fix the
issue, we use ASTContext::getUnqualifiedArrayType instead, which strips
the qualifier off the element type, then reconstruct the array type.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category OpenCL
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants