PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun...

29
Introduction to SPIR for Application and Compiler Developers Yaxun Sam Liu

description

PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu from the AMD Developer Summit (APU13) November 11-13, 2013.

Transcript of PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun...

Page 1: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

Introduction to SPIR for Application and Compiler

Developers

Yaxun Sam Liu

Page 2: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

2 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

OUTLINE

y What is SPIR and why it is useful‒ Why do we need SPIR since we already have LLVM IR

y SPIR for Application Developers‒ How to generate SPIR‒ How to load SPIR‒ Portability considerations using SPIR

y SPIR for Compiler Developers‒ Introduction to SPIR spec‒ How to implement a SPIR loader

y References

Page 3: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

3 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

WHAT IS SPIR

y A Binary Format‒ SPIR means Standard Portable Intermediate Representation‒ A portable binary format for OpenCLTM programs‒ Defined by SPIR spec‒ Based on LLVM IR‒ Supports most of OpenCLTM core features‒ Current version is 1.2, corresponding to OpenCLTM 1.2‒ Developed by Khronos Group, OpenCLTM working group, SPIR subgroup‒ A SPIR binary is bitness aware, means

‒ The pointer size in a SPIR binary is either 32 bit or 64 bit depending on target devices‒ Two sets of SPIR binaries are needed for shipping products in SPIR to both 32 and 64 bit devices

y An extension for OpenCLTM

‒ Defined by SPIR host API‒ Denoted by cl_khr_spir‒ OpenCLTM devices supporting cl_khr_spir is able to load SPIR binary and run it

Page 4: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

4 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

WHY IS SPIR USEFUL

y Why is SPIR useful‒ For Game/Application Developers

‒ Can ship OpenCLTM program in binary instead of source code‒ Can ship just a few binaries for one OpenCLTM program instead of tons of binaries for different platforms/devices

‒ For Compiler Developers‒ Can compile other programming languages to SPIR which can be run on OpenCLTM devices

Page 5: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

5 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO GENERATE SPIR

y SPIR generation is optional for devices supporting cl_khr_spir‒ A device supporting cl_khr_spir is only required to be able to consume SPIR‒ Whether to support SPIR generation is vendors’ choice

y Generating SPIR in host program‒ SPIR spec and host API does not define how to generate SPIR‒ If SPIR generation is supported, it is likely to be done as

‒ Load OpenCLTM source code by clCreateProgramWithSource‒ Compile OpenCLTM source code by clCompileProgram with a vendor specific option for generating SPIR‒ Get the SPIR binary by clGetProgramInfo with CL_PROGRAM_BINARIES‒ Save the SPIR binary to a file

y Generating SPIR by offline compiler‒ Clang 3.3/3.4 can compile OpenCLTM source code to SPIR-like LLVM bitcode‒ A patch for Clang 3.2 is available to Khronos members which can compile OpenCLTM source code to SPIR 1.2‒ Clang options for generating SPIR: -cl-std=CL1.2 -emit-llvm -triple spir[32|64]-unknown-unknown

Page 6: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

6 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO LOAD SPIRLOAD A SINGLE SPIR BINARY

SPIR Binary

cl_program

cl_program

cl_kernel

clBuildProgram

clCreateKernel

clCreateProgramWithBinary

Page 7: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

7 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO LOAD SPIRMULTIPLE SPIR BINARIES, OPENCLTM SOURCE CODES AND VENDOR-SPECIFIC BINARIES

OpenCLTM Source Vendor-specific Binary

cl_program cl_program

cl_program

cl_kernel

clCreateProgramWithSource

clLinkProgram

clCreateKernel

clCreateProgramWithBinary

clCompileProgram

cl_program

SPIR Binary

cl_program

clCreateProgramWithBinary

clCompileProgram

cl_program

Page 8: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

8 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

PORTABILITY CONSIDERATIONS USING SPIR

y Check whether a device supports SPIR‒ Get all supported extensions by clGetDeviceInfo with CL_DEVICE_EXTENSIONS‒ Check whether cl_khr_spir is included

y Supporting both 32 and 64 bit devices‒ Two sets of SPIR binaries are needed, one for 32 bit devices, the other for 64 bit devices‒ Check bitness of a device by clGetDeviceInfo with CL_DEVICE_ADDRESS_BITS‒ Load 32 or 64 bit SPIR binaries accordingly

y Supporting optional extensions‒ Get all supported extensions by clGetDeviceInfo with CL_DEVICE_EXTENSIONS‒ Check if the required extension is supported‒ If yes, load the SPIR binary‒ If no, either fallback to a SPIR binary or OpenCLTM source using only core extensions, or fail gracefully

Page 9: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

9 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

PORTABILITY CONSIDERATIONS USING SPIR

y SPIR binaries generated from non-portable OpenCLTM source is not portable‒ Not following restrictions specified by OpenCLTM spec 1.2 section 6.9 ‒ Casting a pointer from one address space to a different address space‒ Casting an OpenCLTM opaque structure to a different type‒ Performing arithmetic operations or comparison on a sampler‒ Performing sizeof on OpenCLTM opaque structures‒ etc.

Page 10: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

10 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

SPIR FOR COMPILER DEVELOPERS

y Introduction to SPIR spec‒ Relation between SPIR 1.2 and LLVM 3.2‒ Mapping of OpenCLTM to SPIR

‒ Data types‒ Enumeration values‒ Calling conventions‒ Address spaces‒ Name mangling‒ Used extensions‒ Kernel argument info

y How to implement a SPIR loader‒ Overall structure‒ Transforming data types‒ Transforming meta data‒ Demangling and mapping builtin function names

Page 11: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

11 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

RELATION BETWEEN SPIR AND LLVM BITCODE

y SPIR binary is subset of LLVM bitcode‒ A valid SPIR 1.2 binary is valid LLVM 3.2 bitcode‒ SPIR is defined by mapping OpenCLTM C entities to LLVM and also imposing restrictions on LLVM 3.2 bitcode format

‒ Specific target triple and data layout for 32 and 64 bit devices‒ Specific ABI‒ Specific calling conventions‒ Restrictions on allowed instructions, intrinsic functions, linkage types, parameter attributes, visibility styles, function

attributes, etc.

y The ideas behind SPIR‒ To be expressive enough to represent OpenCLTM C programs‒ To carry enough information for OpenCLTM runtime to execute and query the kernels‒ Do not introduce unnecessary entities‒ This may limit SPIR’s expressiveness for other languages, but facilitates development of SPIR loader‒ Balance the burden between SPIR producer and loader

Page 12: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

12 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y OpenCLTM builtin scalar types are mapped to LLVM primitive types‒ bool -> i1‒ char -> i8‒ unsigned char, uchar -> i8‒ short -> i16‒ unsigned short, ushort -> i16‒ int -> i32‒ unsigned int, uint -> i32‒ long -> i64‒ unsigned long, ulong -> i64‒ float -> float‒ double -> double‒ half -> half‒ void -> void

y OpenCLTM builtin vector types are mapped to LLVM vector types‒ charn < n x i8 >‒ ucharn < n x i8 >‒ shortn < n x i16 >‒ ushortn < n x i16 >‒ intn < n x i32 >‒ uintn < n x i32 >‒ longn < n x i64 >‒ ulongn < n x i64 >‒ halfn < n x half >‒ floatn < n x float >‒ doublen < n x double >

DATA TYPES

Page 13: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

13 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y Image and event types are mapped to LLVM opaque structure‒ image1d_t -> %opencl.image1d_t‒ image1d_array_t -> %opencl.image1d_array_t‒ image1d_buer_t -> %opencl.image1d_buer_t‒ image2d_t -> %opencl.image2d_t‒ image2d_array_t -> %opencl.image2d_array_t‒ image3d_t -> %opencl.image3d_t‒ image2d_msaa_t -> %opencl.image2d_msaa_t‒ image2d_array_msaa_t -> %opencl.image2d_array_msaa_t‒ image2d_msaa_depth_t -> %opencl.image2d_msaa_depth_t‒ image2d_array_msaa_depth_t -> %opencl.image2d_array_msaa_depth_t‒ image2d_depth_t -> %opencl.image2d_depth_t‒ image2d_array_depth_t -> %opencl.image2d_array_depth_t‒ event_t -> %opencl.event_t

DATA TYPES

Page 14: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

14 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y Sampler type is mapped to LLVM i32 type‒ Although sampler is represented by integer in SPIR, arithmetic operations and comparison with other values are not

allowed.

y size_t, diffptr_t, intptr_t, uintptr_t is mapped to LLVM i32 or i64 depending on the bitness of SPIR

y Signed/unsignedness of integer types‒ LLVM does not have unsigned integer types‒ OpenCLTM unsigned and signed integer types of the same bit width are mapped to the same type in SPIR‒ If signed/unsignedness of an integer type is needed, usually the information can be obtained through

‒ Mangled function names‒ Sign extension of function arguments and return type‒ Kernel argument metadata

DATA TYPES

Page 15: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

15 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y SPIR uses calling convention to indicate whether a function is a kernel function‒ Kernel functions use spir_kernel calling convention‒ Non-kernel functions use spir_func calling convention‒ No other calling conventions are allowed in SPIR

CALLING CONVENTIONS

Page 16: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

16 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y OpenCLTM C address spaces are mapped to LLVM address spaces‒ Private -> 0‒ Global -> 1‒ Constant -> 2‒ Local -> 3

y Casting a pointer to a different address space is not allowed

y OpenCLTM C function-level local variables are mapped to LLVM module scope global variables‒ The variable name is mapped as <function name>.<variable name>

ADDRESS SPACES

Page 17: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

17 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y SPIR defines enumeration values used by OpenCLTM C programs‒ Image channel order -> same as cl.h‒ Image data type -> same as cl.h‒ Sampler enumeration values (based on cl.h but not exactly the same)

‒ Addressing mode‒ CLK_ADDRESS_NONE=0x0000‒ CLK_ADDRESS_CLAMP_TO_EDGE=0x0002‒ CLK_ADDRESS_CLAMP=0x0004‒ CLK_ADDRESS_REPEAT=0x0006‒ CLK_ADDRESS_MIRRORED_REPEAT=0x0008

‒ Normalized coords‒ CLK_NORMALIZED_COORDS_FALSE=0x0000‒ CLK_NORMALIZED_COORDS_TRUE=0x0001

‒ Filter mode‒ CLK_FILTER_NEAREST=0x0010‒ CLK_FILTER_LINEAR=_0x0020

ENUMERATION VALUES

Page 18: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

18 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y OpenCLTM C builtin functions are mangled

y OpenCLTM C kernel functions and non-kernel user functions are not mangled

y Other languages may choose to mangle non-kernel user functions

y SPIR adopts name mangling scheme of Itanium C++ ABI section 5.1 with extended rules for OpenCLTM C data types, address spaces, access qualifiers‒ Unsigned/signed integer types of the same bit widths are mangled to different names‒ Pointers of non-private address space N -> PU3ASN<mangled element type>‒ Vector type of N elements -> DvN_<mangled element type>‒ OpenCLTM C opaque types (image, sampler, event) -> <string length>ocl_<type name> e.g.

‒ sampler_t -> 11ocl_sampler‒ Access qualifiers: read only -> U1R, write only -> U1W, read write -> U1B‒ size_t and uintptr_t are treated as uint or ulong‒ Ptrdiff_t and intptr_t are treated as int or long

NAME MANGLING

Page 19: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

19 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y SPIR contains information about used optional features and extensions‒ Runtime can reject SPIR binaries using unsupported optional features‒ Application can select SPIR binaries based on used optional features and extensions

y Metadata for used core features‒ openclTM.used.optional.core.features‒ Two core features are allowed:

‒ cl_image: indicates images are used‒ cl_double: indicates doubles are used

y Metadata for used extensions‒ openclTM.used.extensions

‒ cl_khr_int64_base_atomics‒ cl_khr_int64_extended_atomics‒ cl_khr_fp16‒ cl_khr_gl_sharing‒ cl_khr_gl_event‒ etc

USE OF OPTIONAL CORE FEATURES AND EXTENSIONS

Page 20: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

20 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y SPIR contains information about optional kernel attributes‒ Reqd_work_group_size‒ Work_group_size_hint‒ Vec_type_hint

y For each kernel, there is a metadata for optional kernel attributes‒ !opencl.kernels = {!0, !1, ..., !N}

‒ !0 = metadata { < function signature >, !01, !02, ..., , !0i }‒ !1 = metadata { < function signature >, !11, !12, ..., , !1j }‒ ...‒ !N = metadata { < function signature >, !N1, !N2, ..., , !Nk }

KERNEL ATTRIBUTES

Page 21: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

21 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

MAPPING OF OPENCLTM TO SPIR

y SPIR contains kernel argument information required by OpenCLTM runtime for executing kernels

y For each kernel argument, there is metadata‒ kernel_arg_addr_space‒ kernel_arg_access_qual‒ kernel_arg_type‒ kernel_arg_base_type‒ kernel_arg_type_qual‒ kernel_arg_name : optional, only exists if -cl-kernel-arg-info is used when producing SPIR

KERNEL ARGUMENT INFO

Page 22: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

22 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

SPIR ABI

y SPIR uses the default ABI of Clang 3.2‒ Any aggregate type is passed as a pointer. Memory allocation (if needed) is the responsibility of the caller function.‒ Enumeration types are handled as the underlying integer type.‒ If the argument type is a promotable integer type, it will be extended according to the C99 integer promotion rules.‒ Any other type, including floating point types, vectors, etc.. will be passed directly as the corresponding LLVM type.

Page 23: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

23 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO IMPLEMENT SPIR LOADEROVERALL STRUCTURE – IDEAL CASE

y Backend consumes SPIR directly without transforming to vendor’s LLVM format

User’s OpenCLTM Source User’s SPIR Binary Builtin Library Source

SPIR Binary SPIR Binary

Linked SPIR Binary

Executable Kernels

compile compile

Optimize, link

Optimize, codegen

Page 24: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

24 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO IMPLEMENT SPIR LOADEROVERALL STRUCTURE – ACTUAL CASE

y Backend transforms SPIR to vendor’s LLVM format

User’s OpenCLTM Source User’s SPIR Binary Builtin Library Source

Vendor’s LLVM Binary Vendor’s LLVM Binary

Vendor’s Linked Binary

Executable Kernels

compile compile

Optimize, link

Optimize, codegen

Vendor’s LLVM Binary

SPIR loader

Page 25: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

25 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

WHY IS SPIR LOADER NEEDED

y Vendor uses different LLVM entities or format to convey information required by OpenCLTM runtime for querying and executing kernels

y Vendor’s frontend does special transformations which are not done by SPIR producer

y Vendor’s backend is shared by different frontends, some of which do not generate SPIR

y Vendor’s builtin library uses different name mangling scheme

Page 26: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

26 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

HOW TO IMPLEMENT SPIR LOADER

y Verify SPIR target triple and data layout is compatible with target device

y Set target triple for target device

y Demangle builtin functions and re-mangle them using vendor’s name mangling scheme

y Transform data types

y Transform metadata

y Transform calling conventions

y Perform special transformations done by frontend‒ If possible, consider moving the transformations from frontend to backend

Page 27: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

27 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

SPIR CONFORMANCE TEST

y SPIR is a Khronos extension

y To claim supporting SPIR, vendor’s OpenCLTM implementation needs to pass SPIR conformance test

y SPIR 1.2 conformance test is going to be part of OpenCLTM 1.2 conformance test

Page 28: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

28 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

REFERENCES

y Khronos OpenCLTM Working Group SPIR subgroup, SPIR provisional spec http://www.khronos.org/files/opencl-spir-12-provisional.pdf, version 1.2.

y LLVM Team. LLVM Bitcode File Format. http://www.llvm.org/releases/3.2/docs/BitCodeFormat.html, 2012. Version 3.2.

y CodeSourcery, Compaq, EDG, HP, IBM, Intel, Red Hat, SGI, and others. Itanium C++ ABI. http://mentorembedded.github.com/cxx-abi/abi.html .

y Khronos OpenCLTM Working Group. The OpenCLTM Specication, version 1.2. http://www.khronos.org/registry/cl/specs/opencl-1.2.pdf, November 2012.

y LLVM Team. LLVM Language Reference Manual. http://www.llvm.org/releases/3.2/docs/LangRef.html , 2012. Version 3.2.

Page 29: PL-4051, An Introduction to SPIR for OpenCL Application Developers and Compiler Developers, by Yaxun Liu

29 | INTRODUCTION TO SPIR FOR APPLICATION DEVELOPERS AND COMPILER DEVELOPERS | November 5, 2013

DISCLAIMER & ATTRIBUTION

The information presented in this document is for informational purposes only and may contain technical inaccuracies, omissions and typographical errors.

The information contained herein is subject to change and may be rendered inaccurate for many reasons, including but not limited to product and roadmap changes, component and motherboard version changes, new model and/or product releases, product differences between differing manufacturers, software changes, BIOS flashes, firmware upgrades, or the like. AMD assumes no obligation to update or otherwise correct or revise this information. However, AMD reserves the right to revise this information and to make changes from time to time to the content hereof without obligation of AMD to notify any person of such revisions or changes.

AMD MAKES NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE CONTENTS HEREOF AND ASSUMES NO RESPONSIBILITY FOR ANY INACCURACIES, ERRORS OR OMISSIONS THAT MAY APPEAR IN THIS INFORMATION.

AMD SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. IN NO EVENT WILL AMD BE LIABLE TO ANY PERSON FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES ARISING FROM THE USE OF ANY INFORMATION CONTAINED HEREIN, EVEN IF AMD IS EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

ATTRIBUTION

© 2013 Advanced Micro Devices, Inc. All rights reserved. AMD, the AMD Arrow logo and combinations thereof are trademarks of Advanced Micro Devices, Inc. in the United States and/or other jurisdictions. OpenCLTM is a trademark of Apple Inc. Other names are for informational purposes only and may be trademarks of their respective owners.