Address spaces are cast into generic before invoking the constructor.
Details
- Reviewers
Anastasia rjmccall - Commits
- rG9d2872db7495: [OpenCL] Add generic AS to 'this' pointer
rG78de84719be0: [OpenCL] Add generic AS to 'this' pointer
rL349019: [OpenCL] Add generic AS to 'this' pointer
rC349019: [OpenCL] Add generic AS to 'this' pointer
rL348927: [OpenCL] Add generic AS to 'this' pointer
rC348927: [OpenCL] Add generic AS to 'this' pointer
Diff Detail
Event Timeline
lib/CodeGen/CGCall.cpp | ||
---|---|---|
79 | I would suggest taking this opportunity to set up the AST to support declaring methods in an arbitrary address space, so that you can just ask a CXXMethodDecl what address space it's in. You don't have to actually add language support for that — OpenCL C++ would simply change the it to the generic address space instead of the default — but I think that's the right technical approach for implementing this, as opposed to adding a bunch of OpenCL C++ -specific logic all over the compiler that just hardcodes a different address space. | |
4030 | Always use the performAddrSpaceConversion target hook if there's a semantic address-space conversion required. But really, this doesn't seem like the right place to be doing this; it ought to happen higher up when we're adding the this argument to the call, either explicitly in IRGen or implicitly by expecting the object expression to already yield a value in the right address space. I could definitely believe that we don't currently create CastExprs for simple qualification conversions of the object argument of a C++ method call, since (ignoring these address-space conversions) they're always trivial. |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
79 | I quite like this idea. Apart from providing more clean implementation, it opens opportunities for solving several problems that I am trying to understand how to address. Specifically I am trying to find a way to 'overload' methods based on the address space of the object. For example, if an object is created in the address space 1 then programmers should be able to provide a method to be used for objects in such address space for efficiency or even correctness issue. The reasons I am looking at it is that currently C++ doesn't make much sense for address spaces, because we are removing them to generate just one implementation with generic/default address space. However,
I was wondering if a method qualifier is a good language solution for this? For example in OpenCL we could write something like: class foo { public: void bar() __private; // implies bar(__private foo*) void bar() __constant; // implies bar(__constant foo*) }; I guess in C++ it can be done similarly: class foo { public: void bar() __attribute__((address_space(1))); void bar() __attribute__((address_space(2))); }; I would quite like to solve this generically, not just for OpenCL. I think a lot of implementation can be unified/reused then. Without this address spaces seem pretty useless with C++ because they are just cast away to generic/default and no specific address space ends up at the AST level at all. This means implementation will have to rely on the optimizers to recover/deduce address spaces. But I would quite like to provide a way for the developers to manually tune the code for address spaces, just as it was done for OpenCL C. Let me know if you have any thought/suggestions. |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
79 |
Yes, I think that's a very natural extension of C++'s method-qualification rules for const and volatile. Overloads would then be resolved based on which address space was the best match. Now, to briefly take a holistic perspective on the language design, this feature would *strongly* benefit from a way to make a method templated over the address space of this. Unfortunately, I don't think that's reasonable to solve in a language extension; it's really something that needs core language work. That would be a pretty big leap in scope; that said, if you're interested in pursuing it, I'd be happy to share some thoughts on how it'd look, and I think there are several people in the Clang community who could help you with putting a proposal before the committee. |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
4030 | Thanks for the input! It seems like the name performAddrSpaceConversion does not exist in the code-base though. |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
4030 | Sorry, performAddrSpaceCast. |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
79 | Thanks! Yes, I believe some template-based approach could make this a lot more usable. I would be really interested to learn more about your ideas. I would also quite like to see this properly in the spec. I will follow up with you in a separate thread. |
lib/AST/DeclCXX.cpp | ||
---|---|---|
2186–2187 | I feel like the right design now is for getTypeQualifiers() to return a Qualifiers and not just a mask. That will also help identify other places that need to be updated to support address-space qualification. | |
lib/CodeGen/CGCall.cpp | ||
71–72 | Please update the comment to say "ignoring method CVR qualification" instead. Also, maybe we should just eliminate this and use CXXMethodDecl::getThisType. If we want to preserve the micro-optimization of sharing CGFunctionInfos for method types that only differ by CV qualification, maybe we should add a parameter to getThisType to not add ABI-compatible qualification. | |
lib/CodeGen/CGClass.cpp | ||
2020 | This is adding an extra level of pointer, I think. | |
2023 | ...I'm not sure when getLangASFromTargetAS was added, but it shouldn't exist; you need to pass down the language address space of This, which in general will come from the pointer type. And then the AS != LangAS::Default check should just be comparing the constructor's address space to that address space, not specifically LangAS::Default. Same comments apply to the code in commonEmitCXXMemberOrOperatorCall. |
lib/Sema/SemaOverload.cpp | ||
---|---|---|
5254 | Note that this change allowed me to revert some of the CG changes. |
include/clang/AST/DeclCXX.h | ||
---|---|---|
2189 | The address-space qualifier should get stored in the same way on the FunctionProtoType as the other method qualifiers (at least as far as the public interface of FPT goes). It's not the same thing as an ordinary type qualifier on the type, and trying to represent it that way will lead to a lot of problems downstream. You'll probably also have to do some extra work in SemaType to make sure that the attribute gets applied in the right place. You'll need to mess around with the representation of FPT to make this efficient, because we don't want to make every instance of FPT have to pay to store a full Qualifiers. I'd do it like this:
|
lib/Sema/SemaType.cpp | ||
---|---|---|
4817 | Can this be moved into deduceOpenCLImplicitAddrSpace? |
lib/Sema/SemaType.cpp | ||
---|---|---|
4817 | deduceOpenCLImplicitAddrSpace is only wrapping a type with an address space. I also need to make sure the FunctionProtoType gets generated with the address space. |
lib/Sema/SemaType.cpp | ||
---|---|---|
4817 | FunctionProtoType is a type too. Does it go into deduceOpenCLImplicitAddrSpace when creating this? |
I have a lot of comments about various things that need to be fixed, but I just want to take a moment to say that this is a tremendously impressive patch: given only some very high-level directions, you've done a great job figuring out what you needed to do to carry that out and make it work. Really well done.
lib/AST/ASTDumper.cpp | ||
---|---|---|
346 ↗ | (On Diff #176596) | We must have some existing code to print an address space. |
lib/AST/ItaniumMangle.cpp | ||
1507 | You can overload based on the address space, right? I think it needs to be mangled. | |
lib/AST/TypePrinter.cpp | ||
804 ↗ | (On Diff #176596) | You should be printing all the qualifiers here, including address spaces. If you want to suppress an implicit OpenCL address-space qualifier, that seems reasonable. |
lib/CodeGen/CGDebugInfo.cpp | ||
2593 ↗ | (On Diff #176596) | I think this is just GetThisType again. Maybe there should be a version of that takes a record and an FPT; you could make it a static method on CXXMethodDecl. At any rate, I don't think you shouldn't be dropping the address space. |
lib/Index/USRGeneration.cpp | ||
274 | Paging @akyrtzi here. The address-space qualifier should be part of the USR but I don't think if there's a defined schema for that. | |
lib/Parse/ParseCXXInlineMethods.cpp | ||
419 | This should take the full qualifiers. You can see how it ends up getting reassembled into the this type in the CXXThisScopeRAII ctor, and that type definitely needs to be address-space-qualified. | |
lib/Sema/SemaCodeComplete.cpp | ||
1046 | Hmm. This is actually going to break code completion for these methods, I think: IIUC in OpenCL every pointer and l-value is address-space-qualified, so only considering the CVRU qualifiers means that there will always be "extra" qualifiers on the pointer and code completion will think it doesn't match. ...I know code completion isn't your top priority, but this is probably easy enough to fix. | |
3701 | This seems to be intentionally dropping non-CVR qualifiers, and I don't know why you ever would want to do that. | |
lib/Sema/SemaDeclCXX.cpp | ||
11963 | This should definitely not be dropping address spaces. You'll need to make a second patch to handle special members correctly, so you don't need to add a test for this yet, but you might as well get the logic right right now. | |
12332 | Same thing as above. | |
lib/Sema/SemaOverload.cpp | ||
1146 | This is an algorithm that I think you need to get right and which shouldn't drop address spaces. | |
2828 | This is fair to punt to a follow-up patch, but you *should* make that patch. | |
5070 | You should be using the full qualifiers here. | |
lib/Sema/SemaTemplateDeduction.cpp | ||
4660 | Again, this is dropping non-CVR qualifiers for no particular reason. |
Thanks for the feedback, I'll work on fixing the issues!
lib/Sema/SemaOverload.cpp | ||
---|---|---|
1146 | But with this patch we can only have __generic address space for methods. So if I try to implement something here I can't really test it? Or am I missing something? |
lib/AST/ItaniumMangle.cpp | ||
---|---|---|
1507 | Does this refer to our earlier discussion https://reviews.llvm.org/D54862#inline-484509 We don't have a way to qualify methods with an address space yet? I was going to send an RFC to cfe-dev for this but if you think it would be ok to go ahead with an implementation, I am happy with it. Either way would it be better to do this in a separate patch? |
lib/AST/ItaniumMangle.cpp | ||
---|---|---|
1507 | I'm fine with delaying implementation on these two issues until a later patch since, as you say, they can't be tested well until we support arbitrary address-space qualifiers. Please at least leave FIXMEs for them. |
lib/Sema/SemaOverload.cpp | ||
---|---|---|
1146 | Since we didn't add address spaces to the method qualifiers yet, it seems logical to ignore them. Although we could already say, since we would like to add such overloading anyway, it would be logical to return true for the address space qualifiers mismatch just like it's done for CV quals in line 1154. However, I can't think of any way we could test this indeed. |
I uploaded a new patch for most of the comments. I did leave some things out since they need clarification.
lib/AST/ItaniumMangle.cpp | ||
---|---|---|
1507 | I actually did update this, since we can test the mangling of __generic in the test. |
lib/Index/USRGeneration.cpp | ||
---|---|---|
274 | If I understand correctly from other comments you can't add special mangling and USR generation yet and intend to add FIXME for doing mangling support later ? If yes, could you also add FIXME here and re-visit ? |
lib/AST/ItaniumMangle.cpp | ||
---|---|---|
1507 | Great, thanks. Looks good. | |
lib/AST/Type.cpp | ||
2950 ↗ | (On Diff #176831) | The indentation here is messed up. You seem to be mixing up "fast qualifiers" with "CVR qualifiers" in a few places. That's currently correct, in the sense that the fast qualifiers are currently defined to be the CVR qualifiers, but the point of the distinction is that we might want to change that (and we have in fact explored that in the past). I think you should make FunctionTypeBits only claim to store the fast qualifiers, which mostly just means updating a few field / accessor names and changing things like the getCVRQualifiers() call right above this to be getFastQualifiers(). If there are places where it's convenient to assume that the CVR qualifiers are exactly the fast qualifiers, it's okay to static_assert that, but you should make sure to static_assert it in each place you assume it. |
lib/CodeGen/CGDebugInfo.cpp | ||
2593 ↗ | (On Diff #176831) | Why is this getMostRecentCXXRecordDecl instead of getClass? |
lib/CodeGen/CGDeclCXX.cpp | ||
32 | What causes OpenCL C++ declarations to go down this path? | |
lib/Index/USRGeneration.cpp | ||
274 | While you're here, can you described the right way for us to extend USR generation here to potentially add an address space? | |
lib/Parse/ParseDecl.cpp | ||
6166 ↗ | (On Diff #176831) | I think fromCVRUQualifiers is probably the right function, and if that doesn't exist you should add it. |
lib/Sema/SemaExprCXX.cpp | ||
1112 ↗ | (On Diff #176831) | I don't think there's a good reason for this to be dropping non-CVR qualifiers. If there is, it really needs a comment. |
lib/Sema/TreeTransform.h | ||
5276 ↗ | (On Diff #176831) | I think you need to turn ThisTypeQuals into a Qualifiers here. |
lib/AST/Type.cpp | ||
---|---|---|
2950 ↗ | (On Diff #176831) | I'll change it, but I do have a question related to this: Can we make any assumptions with the "fast qualifiers"? I'd like it if we can assume that they fit in 3 bits. Otherwise I think I also need an assertion here. |
lib/CodeGen/CGDebugInfo.cpp | ||
2593 ↗ | (On Diff #176831) | Your initial comment suggested to send in a record rather than a type. But I see now that it may make more sense to use the type directly instead. Will update it. |
lib/CodeGen/CGDeclCXX.cpp | ||
32 | It goes there when we defined an object in __local address space. From the spec "The constructors of a objects in local memory should only be initialized once". This is the same case as with C++ 11 static local variables. |
lib/AST/Type.cpp | ||
---|---|---|
2950 ↗ | (On Diff #176831) | I solved it like this in the end:
|
LGTM, but you can probably undo one of my requests. :)
lib/AST/Type.cpp | ||
---|---|---|
2950 ↗ | (On Diff #176831) | Great, looks good. |
lib/CodeGen/CGDebugInfo.cpp | ||
2593 ↗ | (On Diff #176831) | Oh, I actually didn't even think about the fact that the getClass()) returns a Type* instead of a CXXRecordDecl. Using the record decl is probably better, sorry. |
lib/Index/USRGeneration.cpp | ||
---|---|---|
274 | I'm not familiar with the mechanism, is address space supposed to be identified via a single integer ? If so, then I think adding '-' character plus the integer as character for the address space, immediately after the type qualifiers, should be a way to go. |
I rebased on Friday, and noticed that I broke two tests:
Failing Tests (2):
Clang :: CodeGenOpenCLCXX/template-address-spaces.cl Clang :: SemaOpenCLCXX/address-space-templates.cl
This upload contains a few extra fixes.
lib/Sema/SemaDecl.cpp | ||
---|---|---|
3196 | When merging the class function and the file context function the address space was lost here. | |
lib/Sema/SemaType.cpp | ||
4818 | The first issue was that if a function is declared outside of a class this code did not deduce it. Now it does. | |
lib/Sema/TreeTransform.h | ||
4277 ↗ | (On Diff #177477) | Another place where the address space was removed. |
test/SemaOpenCLCXX/address-space-templates.cl | ||
7 ↗ | (On Diff #177477) | This was the remaining issue that I have not solved yet. It looked like this issue was not so trivial so I think it makes sense to postpone it. |
lib/Sema/SemaType.cpp | ||
---|---|---|
3922 | From the state you can use getDeclarator() that then call a method getContext(). | |
5127 | Rather than passing DeclContext you can get it from the Declarator using getContext() method. | |
lib/Sema/TreeTransform.h | ||
4277 ↗ | (On Diff #177477) | Why OpenCL in the comment, since the code seems to be rather generic. Also not sure this comments adds anything that can't be understood from the code you are adding. |
test/SemaOpenCLCXX/address-space-templates.cl | ||
7 ↗ | (On Diff #177477) | Do you know why it appears twice? |
test/SemaOpenCLCXX/address-space-templates.cl | ||
---|---|---|
7 ↗ | (On Diff #177477) | I believe the main issue is that we have some code that does the following in SemaTemplateInstantiateDecl.cpp: OldTL.getAs<FunctionProtoTypeLoc>() But the implementation of getAs returns nullptr if you have local modifiers. So since this code will always return nullptr we end up taking a different paths. |
lib/Sema/SemaType.cpp | ||
---|---|---|
5127 | Declarator::getContext() returns an enumeration DeclaratorContext which is not enough in this case. |
LGTM! Apart from small improvement that can done before committing if it works at all. :)
lib/Sema/SemaType.cpp | ||
---|---|---|
5127 | Ok, I was wondering if you can use scope clang::NestedNameSpecifier::SpecifierKind to check if something is a method instead of passing DC down. |
Seems like my this commit broke: http://lab.llvm.org:8011/builders/lldb-x86_64-ubuntu-14.04-buildserver/builds/33176
But since I don't really know what anything about lldb, I probably won't be able to fix it fast enough.
/lldb-buildbot/buildServerSlave/lldb-android-buildserver/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp:2208:24: error: no viable overloaded '=' proto_info.TypeQuals = type_quals; ~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~ /lldb-buildbot/buildServerSlave/lldb-android-buildserver/llvm/tools/clang/include/clang/AST/Type.h:141:7: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'unsigned int' to 'const clang::Qualifiers' for 1st argument class Qualifiers { ^ /lldb-buildbot/buildServerSlave/lldb-android-buildserver/llvm/tools/clang/include/clang/AST/Type.h:141:7: note: candidate function (the implicit move assignment operator) not viable: no known conversion from 'unsigned int' to 'clang::Qualifiers' for 1st argument 1 error generated.
I think it can be easily solved by Qualifiers::fromFastMask(type_quals); also updating the variable name since it changed.
But I know nothing about lldb, so I better revert this patch for now.
include/clang/AST/Type.h | ||
---|---|---|
3692 | You can use FunctionType::FunctionTypeExtraBitfields |
I think that's exactly what you need to do, and you'd be welcome to commit that instead of reverting this.
lib/Index/USRGeneration.cpp | ||
---|---|---|
274 | Okay. Some of them are integers; others are identified in the language as more of a keyword and so there's no stable mapping from an integer value. Should we just come up with some simple schema for that following - that's unambiguous with a digit? |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
75 | I'm a bit late to the party, but shouldn't this be MD->getTypeQualifiers().getAddressSpace()? |
lib/CodeGen/CGCall.cpp | ||
---|---|---|
75 | Yes, you're right, it should. |
I'm also a bit confused about the semantics that this patch is applying to function types. It mostly seems to concern the extra trailing Qualifiers on CXXMethodDecl to store the addrspace quals, but in some places (SemaType:4842, SemaDecl:3198) it seems to be applying the address space to the function type itself, which certainly seems like something else to me. A function with an address space qualified type would (to me, at least) be a function *located* in that address space, not one qualified to take a this from that address space.
Yeah, there may be some confusion about that, and unfortunately it's easy to miss in the review.
But yes, I agree that address-space qualifiers are in principle one of the few qualifiers that make sense to be able to have (in a normal way) on function types.
The address-space qualifier should get stored in the same way on the FunctionProtoType as the other method qualifiers (at least as far as the public interface of FPT goes). It's not the same thing as an ordinary type qualifier on the type, and trying to represent it that way will lead to a lot of problems downstream.
You'll probably also have to do some extra work in SemaType to make sure that the attribute gets applied in the right place.
You'll need to mess around with the representation of FPT to make this efficient, because we don't want to make every instance of FPT have to pay to store a full Qualifiers. I'd do it like this: