According to AMD the Intermediate Language (IL) is an abstract representation for hardware vertex, pixel, and geometry shaders, as well as compute kernels that can be taken as input by other modules implementing the IL. An IL compiler uses an IL shader or kernel in conjunction with driver state information to translate these shaders into hardware instructions(ISA).
There are two options for generating the IL from a *.cl file.
(i)Setting the environment variable:
(ii)Using the build options:
In clBuildProram() specify ”-save-temps” in the build option field to generate IL and ISA.
On a linux system the IL and ISA files will be saved in the current working directory in both of the cases.
AMD does not provide any official method for building programs directly form IL codes. Therefore if you want to make some adjustments in the generated IL and then build the program from the modified IL ,you need to follow the given steps:
(i) Generate default AMD binaries. AMD binaries are ELF objects having the following major sections.
.amdil -This section contains the default IL codes
.text -This section contains the default ISA
.source -This section contains the default *.cl source
.llvmir -This section contains the intermediate representaion. If the target device is CPU the LLVMIR is converted to x86 codes by LLVM AS . If the target device is a GPU then LLVM IR is converted AMD IL.
All of the above the section except .amdil are unnecessary. So to generate binaries without them we need to specify the option ”-fno-bin-llvmir -fno-bin-source -fno-bin-exe -fbin-amdil” to the clBuildProgram().This will generate a binary containg only the .amdil section.
(ii) Update the .amdil section in the binaries generated in previous step using libelf API. In this step we replace the original AMD IL codes with our own implemntation.
(iii) Update the .symtab section in the same binary using libelf API. This is for maintaing the integrity of the binary file so that it can be recognized by openCL compiler.
(iv) Build the program from generarted openCL binaries using clCreateProgramWithBinary().
To compile this program you need to have libelf-devel installed in your sytem.
This is the syntax for generating the executable using gcc.
gcc -o clbingenerate clbingenerate.c -lelf /usr/lib/libOpenCL.so -I$AMDAPPSDKROOT/include
To compile the program syntax is.
gcc -o clbinuse clbinuse.c /usr/lib/libOpenCL.so -I$AMDAPPSDKROOT/include
I will explain how to use the above two programs using an example.
Extract the files in above archive in the same folder as the above two programs.
Inside the the archive there is one simple program to multiply 0-100 numbers by 2. The 'kernel.cl' contains the program and 'default.il' is the default IL generated from this kernel. However in test.il, I have modified one instruction and also added one extra instruction to give a net result of multiplication by 8. The changes are at line number 72 and 73 in the IL codes.
generateAmdBin(unsigned int platform_id , unsigned int dev_id,char *clFile,char *binFile,char *ilFile);
platform_id -platform id of target platform. i.e choose a platform For ex. 0 will choose platform 0
dev_id -device id of taget platform. i.e choose a device in the platform.
clFile -Source file which will be used to generate default AMD binaries.For ex 'kernel.cl'
binFile -Name of the binary file to be genearted.For ex 'kernel.bin.0'
ilFile -name of the modified IL file. If this field is NULL a default binary will be generated conating the default IL codes. But if you specify an il file ,the .amdil section of the binay will be modified by this file.For ex 'test.il'
Note: The above archive contains the IL generated on a 4890. So to generate IL codes compatible with your hardware you must pass NULL in the 'ilFile' field mentioned above. This will generate _temp_0_xxx_test.il along with other temporary files. Where xxx is the name of your device. Modify this generated il file as required and rename it 'test.il'.
Run the program:
This will generate a binary named 'kernel.bin.0'
buildProgramFromAmdBin(unsigned int platform_id,unsigned int dev_id,char *binFile);
platform_id -platform id of the target platform for which the binary is built.
dev_id -device id of the target platform for which binary is built.
binFile -Name of the binary file for reading. For ex 'kernel.bin.0'
Run the program:
This will produce the outputs.
(i) Binary file generated for one device is incompatible with another device. Eg binary generated for 4890 is incompatible with 7970. Even binary generated for 7970 should be incompatible with 7870 etc. However binary generated for 7970 should be compatible with 7950.
(ii) Binary generated on 64bit sytem is incompatible with 32bit systems and vice versa.
(iii) The above codes will work correctly if the *.cl file contains only one kernel. This is however, only the limitation of my codes.