[cfe-dev] Allow implicit copy constructor between address spaces in C++
David Chisnall
David.Chisnall at cl.cam.ac.uk
Sat May 3 06:40:58 PDT 2014
It looks correct to reject this. Pointers to different address spaces can't be used interchangeably - they can require different instructions to load and store, depending on the architecture, and for disjoint address space there may be no mechanism for translating an address from one to the other.
For C, this is fine because we just emit an llvm.memcpy from one address space to the other[1], which can be turned into a sequence of loads from one address space and stores to the other.
For C++, with a non-trivial copy constructor, you'd have to provide a copy constructor for each possible source address space. With a the default copy constructor, you'd have to teach clang that it should be providing a default copy constructor for each possible address space. I'm not sure this would even be the correct thing to do, because some classes may not support copying between address spaces and so there's a lot of complexity that you'd have to think about before proposing a correct model for the language to support.
David
[1] SelectionDAG then fairly consistently does the wrong thing for this in certain cases, and I really should get around to cleaning up and upstreaming the patches to fix it.
On 3 May 2014, at 14:17, Adam Strzelecki <ono at java.pl> wrote:
> Hello,
>
> It is completely legit to initialize (copy) between address spaces in C while it fails in C++. This makes address spaces completely unusable in C++, at least I don't see any way to copy initialize in C++.
>
> The reason being is I am trying to use OpenCL++ (OpenCL in C++11 mode), which works pretty fine [minor changes to Clang], except being unable to initialize from __global to __private.
>
> Please consider following code:
>
> // RUN: %clang_cc1 -fsyntax-only -verify %s
> struct Point {
> float x, y;
> };
>
> typedef struct Point Point;
> typedef struct Point Point_1 __attribute__((address_space(1)));
>
> float test(int i, const Point_1 *a) {
> Point r = a[i];
> return r.x * r.y;
> }
>
>
> Running it in `-x c` works fine, running with `-x c++ -std=c++11` generates:
>
> File test.cc Line 3: candidate constructor (the implicit copy constructor) not viable: 1st argument ('const Point_1' (aka 'const __attribute__((address_space(1))) Point')) is in address space 1, but parameter must be in address space 0
> File test.cc Line 3: candidate constructor (the implicit move constructor) not viable: 1st argument ('const Point_1' (aka 'const __attribute__((address_space(1))) Point')) is in address space 1, but parameter must be in address space 0
> File test.cc Line 3: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
>
>
>
> Can anyone point me any workaround, or how to fix it in Clang code? I believe this has to be relaxed in SemaOverload.cpp TryCopyInitialization, but I wish to not try solution that wouldn't be accepted into upstream.
>
>
> FYI I have tried reinterpret_cast hinted in tests/SemaCXX/address-space-conversion.cpp:
>
> Point r = reinterpret_cast<const Point *>(a)[i]
>
> But I believe emitted ll is INVALID, since @llvm.memcpy looses address space qualifier for source pointer:
>
> %7 = getelementptr inbounds %struct.Point* %6, i64 %4
> %8 = bitcast %struct.Point* %r to i8*
> %9 = bitcast %struct.Point* %7 to i8*
> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %8, i8* %9, i64 8, i32 4, i1 false)
>
> Comparing to ll emitted in plain C mode:
>
> %6 = getelementptr inbounds %struct.Point addrspace(1)* %5, i64 %4
> %7 = bitcast %struct.Point* %r to i8*
> %8 = bitcast %struct.Point addrspace(1)* %6 to i8 addrspace(1)*
> call void @llvm.memcpy.p0i8.p1i8.i64(i8* %7, i8 addrspace(1)* %8, i64 8, i32 4, i1 false)
>
>
>
> Regards,
> --
> Adam
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
More information about the cfe-dev
mailing list