From: metafoo at gmail.com [mailto:metafoo at gmail.com] On Behalf Of Richard Smith Sent: Wednesday, September 12, 2012 2:51 PM To: Villmow, Micah Cc: Ouriel, Boaz; cfe-dev at cs.uiuc.edu; llvmdev at cs.uiuc.edu Subject: Re: [LLVMdev] SPIR Portability Discussion On Wed, Sep 12, 2012 at 2:23 PM, Villmow, Micah <Micah.Villmow at amd.com<mailto:Micah.Villmow at amd.com>> wrote: From: llvmdev-bounces at cs.uiuc.edu<mailto:llvmdev-bounces at cs.uiuc.edu> [mailto: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<mailto:cfe-dev at cs.uiuc.edu>; llvmdev at cs.uiuc.edu<mailto: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<mailto: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). [Villmow, Micah] OpenCL restricts this behavior, so it is illegal. Another case which might depend on this: enum E { a = sizeof(void*) // is this valid? }; [Villmow, Micah] I will have to think on this one, good example. 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? [Villmow, Micah] OpenCL C defines 'int' to be 32bits irrespective of the host/device bitness. So this would follow the normal integer promotion rules. 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/810ec6bc/attachment.html>
On Wed, Sep 12, 2012 at 2:58 PM, Villmow, Micah <Micah.Villmow at amd.com> wrote:> 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? > > [Villmow, Micah] OpenCL C defines ‘int’ to be 32bits irrespective of the > host/device bitness. So this would follow the normal integer promotion > rules.I think you're misunderstanding the issue: the point is, is "sizeof(int) + -8LL < 0" true or false? -Eli
On Wed, Sep 12, 2012 at 2:58 PM, Villmow, Micah <Micah.Villmow at amd.com>wrote:> ** ** > > ** ** > > *From:* metafoo at gmail.com [mailto:metafoo at gmail.com] *On Behalf Of *Richard > Smith > *Sent:* Wednesday, September 12, 2012 2:51 PM > *To:* Villmow, Micah > *Cc:* Ouriel, Boaz; cfe-dev at cs.uiuc.edu; llvmdev at cs.uiuc.edu > > *Subject:* Re: [LLVMdev] SPIR Portability Discussion**** > > ** ** > > 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). > **** > > *[Villmow, Micah] OpenCL restricts this behavior, so it is illegal.* > > Another case which might depend on this:**** > > ** ** > > enum E {**** > > a = sizeof(void*) // is this valid?**** > > };**** > > *[Villmow, Micah] I will have to think on this one, good example.***** > > ** ** > > 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?**** > > *[Villmow, Micah] OpenCL C defines ‘int’ to be 32bits irrespective of the > host/device bitness. So this would follow the normal integer promotion > rules.* >The value of sizeof(int) isn't what's relevant here. This code implicitly depends on sizeof(sizeof(int)): if size_t is a 32 bit unsigned type, then sizeof(int) + 1LL has a 64-bit signed type. If it's a 64 bit unsigned type, then sizeof(int) + 1LL has a 64-bit *unsigned* type. For instance, the value of "-1LL < sizeof(int) + 1LL" is 1 on 32-bit and 0 on 64-bit. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120912/469fa515/attachment.html>
> -----Original Message----- > From: Eli Friedman [mailto:eli.friedman at gmail.com] > Sent: Wednesday, September 12, 2012 3:22 PM > To: Villmow, Micah > Cc: Richard Smith; cfe-dev at cs.uiuc.edu; llvmdev at cs.uiuc.edu > Subject: Re: [cfe-dev] [LLVMdev] SPIR Portability Discussion > > On Wed, Sep 12, 2012 at 2:58 PM, Villmow, Micah <Micah.Villmow at amd.com> > wrote: > > 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? > > > > [Villmow, Micah] OpenCL C defines 'int' to be 32bits irrespective of > the > > host/device bitness. So this would follow the normal integer > promotion > > rules. > > I think you're misunderstanding the issue: the point is, is > "sizeof(int) + -8LL < 0" true or false?[Villmow, Micah] Yep, I don't see why this is any different than "4 + -8LL < 0". OpenCL C, and in turn SPIR, defines sizeof(int) == 4. While this might be a problem in C, this isn't an issue in OpenCL since there is no variance in the sizeof(int) across devices.> > -Eli