<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 12 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link=blue vlink=purple><div class=WordSection1><p class=MsoNormal>One of the projects I am working on with others is to make LLVM-IR endian agnostic. <o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>So, I am sending out this proposal for feedback to the LLVM community. I’ve attached<o:p></o:p></p><p class=MsoNormal>pretty version of the proposal in PDF format and pasted a 80-column safe text version<o:p></o:p></p><p class=MsoNormal>below. <o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>I’m looking forward to comments and feedback.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Thanks,<o:p></o:p></p><p class=MsoNormal>Micah Villmow<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Text of Proposal:<o:p></o:p></p><p class=MsoNormal>================================================================================<o:p></o:p></p><p class=MsoNormal>RFC - ENDIAN AGNOSTIC IR REPRESENTATION.<o:p></o:p></p><p class=MsoNormal>================================================================================<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>MOTIVATION:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>    In our current compilation model, a compiler will compile from a source <o:p></o:p></p><p class=MsoNormal>language to an intermediate IR representation, perform optimizations, and then<o:p></o:p></p><p class=MsoNormal>use the LLVM code generation infrastructure to target a specific backend. This<o:p></o:p></p><p class=MsoNormal>approach works well for homogenous devices, but compilation models of compute<o:p></o:p></p><p class=MsoNormal>languages, like OpenCL,  now take place with heterogeneous devices(e.g. x86 <o:p></o:p></p><p class=MsoNormal>core + gpu) as the targets. In some cases the devices have varying pointer <o:p></o:p></p><p class=MsoNormal>sizes and byte ordering and this causes a problem for cross-device binary <o:p></o:p></p><p class=MsoNormal>compatibility that a source language provides.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    The major problem is that when creating a program for a heterogeneous <o:p></o:p></p><p class=MsoNormal>system, different compilation paths are required for different devices for <o:p></o:p></p><p class=MsoNormal>each source compilation. OpenCL, an Open Standard for compute on various types<o:p></o:p></p><p class=MsoNormal>of devices, defines a source language that is portable across devices(i.e. <o:p></o:p></p><p class=MsoNormal>same source on GPU's and CPUs). While compilation from source is portable, <o:p></o:p></p><p class=MsoNormal>compilation from binary is not, and diverging compilation paths have issues<o:p></o:p></p><p class=MsoNormal>with both maintenance and testing. <o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>PROBLEM QUESTION:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>How does a vendor simplify the compiler stack across multiple target devices<o:p></o:p></p><p class=MsoNormal>by removing endianess from the IR representation?<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>PROPOSAL:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>I am proposing an extension to LLVM[1] that abstracts away all endian related<o:p></o:p></p><p class=MsoNormal>IR operations with a series of intrinsic calls. These intrinsic calls allow<o:p></o:p></p><p class=MsoNormal>consumers of the IR to quickly reconstruct either the original IR, or an <o:p></o:p></p><p class=MsoNormal>equivalent IR, with respect to the byte ordering of the target device. This IR<o:p></o:p></p><p class=MsoNormal>representation provides an abstraction layer similar to the hton[sl]() series <o:p></o:p></p><p class=MsoNormal>of function calls with network programming.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>OTHER SYSTEMS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>While this approach is similar to Google's PNaCl[3] which attempts to provide <o:p></o:p></p><p class=MsoNormal>an ISA neutral representation. The goals of this proposal are slightly <o:p></o:p></p><p class=MsoNormal>different in that we not only want ISA neutral representation, but also <o:p></o:p></p><p class=MsoNormal>endian-neutral representation. Therefore, where PNaCl represents LLVM-IR <o:p></o:p></p><p class=MsoNormal>before codegen, see figure 1 from [3],  this approach provides a portable <o:p></o:p></p><p class=MsoNormal>representation after the frontend and before LLVM-bitcode generation. The <o:p></o:p></p><p class=MsoNormal>PNaCl representation makes assumptions on address space, data types,<o:p></o:p></p><p class=MsoNormal>byte-order, concurrency and runtime system. This proposal inherits the <o:p></o:p></p><p class=MsoNormal>assumptions on data types, address sizes, concurrency and runtime systems <o:p></o:p></p><p class=MsoNormal>from OpenCL[4].<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>DEFINITIONS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>Global Memory - Memory that is visible to all threads in a process/program, <o:p></o:p></p><p class=MsoNormal>e.g. video ram. This includes all read-only, write-only and read-write memories<o:p></o:p></p><p class=MsoNormal>on the system that are visible to all threads.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>INTRINSICS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>This proposal introduces new sets of intrinsics, two load intrinsics and two <o:p></o:p></p><p class=MsoNormal>store intrinsics. The sets are as follows:<o:p></o:p></p><p class=MsoNormal>declare <type> @llvm.portable.load.e.<type>(<type>* ptr, , i32 alignment, <o:p></o:p></p><p class=MsoNormal>i1 host, i1 atomic, i1 volatile, i1 nontemporal, i1 singlethread) <o:p></o:p></p><p class=MsoNormal>// little endian load<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>declare <type> @llvm.portable.load.E.<type>(<type>* ptr, i32 alignment, <o:p></o:p></p><p class=MsoNormal>i1 host,  i1 atomic, i1 volatile, i1 nontemporal, i1 singlethread) <o:p></o:p></p><p class=MsoNormal>// big endian load<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>declare void @llvm.portable.store.e.<type>(<type> data, <type>* ptr, <o:p></o:p></p><p class=MsoNormal>i32 alignment, i1 host,  i1 atomic, i1 volatilei1 nontemporal, <o:p></o:p></p><p class=MsoNormal>i1 singlethread) // little endian store<o:p></o:p></p><p class=MsoNormal>declare void @llvm.portable.store.E.<type>(<type> data, <type>* ptr, <o:p></o:p></p><p class=MsoNormal>i32 alignment, i1 host, i1 atomic, i1 volatile, i1 nontemporal, <o:p></o:p></p><p class=MsoNormal>i1 singlethread) // big endian store<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>A second smaller set could be:<o:p></o:p></p><p class=MsoNormal>declare <type> @llvm.portable.load.<type>(<type>* ptr, i32 alignment,<o:p></o:p></p><p class=MsoNormal>i1 host, i1 littleEndian, i1 atomic, i1 volatile,<o:p></o:p></p><p class=MsoNormal>i1 nontemporal, i1 singlethread)<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>declare void @llvm.portable.store.<type>(<type> data, <type>* ptr, <o:p></o:p></p><p class=MsoNormal>i32 alignment, i1 host, i1 littleEndian, i1 atomic, i1 volatile, <o:p></o:p></p><p class=MsoNormal>i1 nontemporal, i1 singlethread)<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>    Valid values for type are scalar sizes i8, i16, i32, i64, f16, f32, f64 and <o:p></o:p></p><p class=MsoNormal>vector versions with sizes of 2, 3, 4, 8 and 16 elements. Only pointers to the <o:p></o:p></p><p class=MsoNormal>global address space, designated to separate it from the default address space <o:p></o:p></p><p class=MsoNormal>in LLVM which is 0, with the pointer address space 1, are valid pointer values.<o:p></o:p></p><p class=MsoNormal>The reason for the different address space is that requirement in OpenCL that <o:p></o:p></p><p class=MsoNormal>the default address space is private memory, which conflicts with LLVM's <o:p></o:p></p><p class=MsoNormal>default memory going to globally visible memory. For brevity, all possible <o:p></o:p></p><p class=MsoNormal>combinations are not enumerated here.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Another issue is with the data layout. A third option to the endianess is <o:p></o:p></p><p class=MsoNormal>added to the LLVM reference manual that is defined as follows.<o:p></o:p></p><p class=MsoNormal>"p Specifies that the IR is in endian-portable form, i.e. code produced by <o:p></o:p></p><p class=MsoNormal>little- and big-endian target back ends will be functionally equivalent (in <o:p></o:p></p><p class=MsoNormal>their affect on global memory).  The IR must be converted to a target format<o:p></o:p></p><p class=MsoNormal>before the IR is valid LLVM-IR."<o:p></o:p></p><p class=MsoNormal>Using this data layout option will allow the compiler to quickly determine <o:p></o:p></p><p class=MsoNormal>if the IR is in endian portable form.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>PARAMETERS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>host - True when the load/store is from the host machine and false when the <o:p></o:p></p><p class=MsoNormal>load/store is from the device.<o:p></o:p></p><p class=MsoNormal>atomic/volatile/nontemporal/singlethread - Follows the same semantics as the <o:p></o:p></p><p class=MsoNormal>arguments to the load/store instructions in the LLVM-IR with the same names. <o:p></o:p></p><p class=MsoNormal>See the LLVM Lang Ref[1].<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>POINTER ATTRIBUTES:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>In OpenCL, a pointer can have attributes attached, and this information needs <o:p></o:p></p><p class=MsoNormal>to be encoded. In LLVM, the method of encoding extra information is via <o:p></o:p></p><p class=MsoNormal>metadata nodes and this is used so that the intrinsic do not need to be <o:p></o:p></p><p class=MsoNormal>modified to add extra information. One example of this is the endian(host) <o:p></o:p></p><p class=MsoNormal>attribute that can be attached to a pointer argument(see 6.10.3 of OpenCL <o:p></o:p></p><p class=MsoNormal>1.1 spec). This information can be encoded in a metadata node which is attached<o:p></o:p></p><p class=MsoNormal>to the intrinsic.  An example encoding of this information is as follows:<o:p></o:p></p><p class=MsoNormal>!0 = metadata !{<o:p></o:p></p><p class=MsoNormal>  i32, ;; Tag = <OpenCL version number> using the official OpenCL version macro<o:p></o:p></p><p class=MsoNormal>  i1,;;Boolean value to specify that load is from host on true, device on false<o:p></o:p></p><p class=MsoNormal>  metadata ;; List of attributes for this intrinsic instruction<o:p></o:p></p><p class=MsoNormal>}<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>CONSTRAINTS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>Except for the data and ptr arguments, all arguments must be compile time <o:p></o:p></p><p class=MsoNormal>constants.<o:p></o:p></p><p class=MsoNormal>Optimizations that rely on the byte ordering of memory or that modify the <o:p></o:p></p><p class=MsoNormal>programs interactions with global memory are illegal to be performed on the <o:p></o:p></p><p class=MsoNormal>IR when in the portable form.<o:p></o:p></p><p class=MsoNormal>All accesses to global memory must be done through these intrinsic calls.<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>LINKS:<o:p></o:p></p><p class=MsoNormal>-------------------------------------------------------------------------------<o:p></o:p></p><p class=MsoNormal>1.            http://llvm.org/docs/LangRef.html<o:p></o:p></p><p class=MsoNormal>2.            http://llvm.org/docs/Atomics.html<o:p></o:p></p><p class=MsoNormal>3.            http://nativeclient.googlecode.com/svn/data/site/pnacl.pdf<o:p></o:p></p><p class=MsoNormal>4.            http://www.khronos.org/opencl/<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p></div></body></html>