[LLVMdev] SPIR Portability Discussion
Richard Smith
richard at metafoo.co.uk
Wed Sep 12 14:51:06 PDT 2012
On Wed, Sep 12, 2012 at 2:23 PM, Villmow, Micah <Micah.Villmow at amd.com>wrote:
> ** **
>
> ** **
>
> *From:* llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu] *On
> Behalf Of *Richard Smith
> *Sent:* Wednesday, September 12, 2012 1:55 PM
> *To:* Ouriel, Boaz
> *Cc:* cfe-dev at cs.uiuc.edu; llvmdev at cs.uiuc.edu
> *Subject:* Re: [LLVMdev] SPIR Portability Discussion****
>
> ** **
>
> On Wed, Sep 12, 2012 at 12:27 PM, Ouriel, Boaz <boaz.ouriel at intel.com>
> wrote:****
>
> Hey All,
>
> This is a very big topic in SPIR and probably a very controversial one as
> well. It includes dealing with 32 vs. 64 bit architectures and OpenCL "C"
> endianness.
> We have written down some of the aspects, but of course did not cover
> everything - let's start a discussion on the portability and see where it
> takes us.
> I suggest we start with the 32 vs. 64 bits discussion and then move to the
> Endianness part.
>
> ****Introduction****
> As a reminder, portability is one of SPIR's goals.
> However, SPIR does not attempt to solve inherent portability issues, which
> exist in OpenCL "C" or in C99.
> It is clear that OpenCL programs could be written in a way which make them
> non portable and very device specific.
> Such programs will never be portable. In addition, some corner case
> scenario's which have been identified by Khronos members have been
> disallowed in SPIR.
> So, SPIR aims at being portable but not for every scenario.
>
> 1) ****Portability between Devices with different address width (32 vs. 64
> bits)****
> During the design stages, Khronos members needed to decide on its
> philosophy when it comes to dealing with the address width of devices (32
> vs. 64bits).
> During internal discussions, two alternatives came up. The first
> alternative was to split SPIR into two sub-cases: SPIR 32bits and SPIR
> 64bits.
> The second alternative was to try and abstract this information at SPIR
> level.
>
> Splitting SPIR into 32bit and 64bit is simpler to implement. However, it
> is less portable.
> This will require OpenCL developers to pre-compile two versions of their
> code one for 32bit and another for 64bit devices and make their application
> aware at runtime to the underlying device architecture.
> OpenCL applications would need to load the proper SPIR binary based on the
> device architecture.
> An option that was raised during the discussions was to have a fat binary
> that contains both 32bit and 64bit versions of SPIR binaries.
> However, this option was controversial inside Khronos and eventually was
> not accepted.
> The decision was to pursue the second alternative. Khronos members
> understand that this is a more complex alternative and does not guarantee
> 100% percent coverage to all cases.
> However, as stated before, SPIR attempts to solve the important cases.
> Those particular cases which SPIR will not be able to address are
> explicitly documented in the specification.
>
> ****Pointers****
> During SPIR generation, the size, and the alignment of pointers is unknown
> (32 vs. 64 bits).
> The SPIR representation shouldn't assume anything about the size and the
> alignment of pointers,
> but it might use pointers in the usual way (except from using GEP when the
> pointed type has unknown size - this one is illegal in SPIR and will fail
> the SPIR verification pass which was written by Khronos members)
>
> *****Sizeof******
> Most valid built-in and user specific types in OpenCL have known non
> device-specific size.
> However, for some types (pointers, size_t, ptrdiff_t) the size is unknown
> during compilation.
> To overcome this issue, SPIR provides functions to substitute the constant
> values of the sizeof operator.
> These functions should be resolved by the device backend compiler when
> producing the final machine code of the OpenCL program.****
>
> ** **
>
> OpenCL 1.2 (6.3)/k says the result of sizeof is an ICE. So these are valid:
> ****
>
> ** **
>
> int does_this_compile[sizeof(void*) - 3];
>
Oops, I meant sizeof(void*) - 5.
> ****
>
> *[Villmow, Micah] ‘ICE’? Integer compile time expression? While not
> pretty, this can be represented in SPIR with the following sequence on
> instructions*
>
> *%1 = call %spir.size_t @__spir_sizet_convert_size_t(i32 3)*
>
> *%2 = call %spir.size_t @__spir_size_of_sizet()*
>
> *%3 = call %spir.size_t @__spir_sizet_sub(%spir.size_t %1, %spir.size_t
> %2)*
>
> *%4 = call %spir.size_t @__spir_sizet_convert_i32(%spir.size_t %3)*
>
> *%5 = alloca i32, i32 %4*
>
My point here was that if sizeof(void*) is an integer constant expression,
then this code has a constraint violation if sizeof(void*) is 4 but not if
sizeof(void*) is 8 (and my example was intended to be of a global array,
not a function-local one, so you can't fall back to treating it as a VLA).
Another case which might depend on this:
enum E {
a = sizeof(void*) // is this valid?
};
Based on the behavior you describe above, it looks like sizeof applied to a
pointer (and to size_t etc.) isn't a constant expression in SPIR's model.
Another factor to consider, with size_t etc as defined in SPIR, is the
usual arithmetic conversions. For instance (assuming a 64-bit long long),
sizeof(int) + 1LL would be signed if size_t is 32 bits wide, and would be
unsigned if size_t is 64 bits wide. How is this handled?
> How do you perform record layout if the size of a pointer is unknown? For
> instance:
>
> **
>
> ** **
>
> struct A {****
>
> int *p;****
>
> int n;****
>
> } a;****
>
> int arr[offsetof(A, n) - 3]; // or, int arr[(char*)&a.n - (char*)&a.p - 3];
> ****
>
> *[Villmow, Micah] Since in the current implementation of SPIR, a pointer
> is defined as 64bits when in a structure(SPIR spec 2.1.5), the offsets
> themselves are well defined.*
>
I see, that makes sense.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120912/06aadc50/attachment.html>
More information about the llvm-dev
mailing list