2022-09-22 16:55:35 +00:00
/*
2025-09-04 17:06:09 +00:00
* Copyright ( C ) 2022 - 2025 Intel Corporation
2022-09-22 16:55:35 +00:00
*
* SPDX - License - Identifier : MIT
*
*/
# include "shared/offline_compiler/source/ocloc_interface.h"
# include "shared/offline_compiler/source/decoder/binary_decoder.h"
# include "shared/offline_compiler/source/decoder/binary_encoder.h"
2022-08-23 15:20:14 +00:00
# include "shared/offline_compiler/source/decoder/zebin_manipulator.h"
2022-09-22 16:55:35 +00:00
# include "shared/offline_compiler/source/multi_command.h"
2023-09-05 17:13:13 +00:00
# include "shared/offline_compiler/source/ocloc_api.h"
2022-09-22 16:55:35 +00:00
# include "shared/offline_compiler/source/ocloc_concat.h"
# include "shared/offline_compiler/source/ocloc_fatbinary.h"
# include "shared/offline_compiler/source/ocloc_validator.h"
# include "shared/offline_compiler/source/offline_compiler.h"
# include "shared/offline_compiler/source/offline_linker.h"
# include "shared/offline_compiler/source/utilities/safety_caller.h"
2022-08-23 15:20:14 +00:00
# include "shared/source/device_binary_format/elf/elf_decoder.h"
2025-10-22 23:18:58 +00:00
# include "shared/source/helpers/product_config_helper_former.h"
2024-08-13 15:26:18 +00:00
# include "shared/source/os_interface/os_library.h"
2022-09-22 16:55:35 +00:00
2025-10-22 23:18:58 +00:00
# include "neo_aot_platforms.h"
2022-09-22 16:55:35 +00:00
# include <memory>
namespace Ocloc {
using namespace NEO ;
2023-09-04 18:14:23 +00:00
void printOclocCmdLine ( OclocArgHelper & wrapper , const std : : vector < std : : string > & args ) {
2025-09-04 17:06:09 +00:00
auto areQuotesRequired = [ ] ( std : : string_view argName ) - > bool {
2022-09-22 16:55:35 +00:00
return argName = = " -options " | | argName = = " -internal_options " ;
} ;
2023-09-04 18:14:23 +00:00
wrapper . printf ( " Command was: " ) ;
2022-09-22 16:55:35 +00:00
bool useQuotes = false ;
for ( auto & currArg : args ) {
if ( useQuotes ) {
2023-09-04 18:14:23 +00:00
wrapper . printf ( " \" %s \" " , currArg . c_str ( ) ) ;
2022-09-22 16:55:35 +00:00
useQuotes = false ;
} else {
2023-09-04 18:14:23 +00:00
wrapper . printf ( " %s " , currArg . c_str ( ) ) ;
2022-09-22 16:55:35 +00:00
useQuotes = areQuotesRequired ( currArg . c_str ( ) ) ;
}
}
2023-09-04 18:14:23 +00:00
wrapper . printf ( " \n " ) ;
2022-09-22 16:55:35 +00:00
}
2023-09-04 18:14:23 +00:00
void printHelp ( OclocArgHelper & wrapper ) {
2022-09-22 16:55:35 +00:00
const char * help = R " ===(ocloc is a tool for managing Intel Compute GPU device binary format.
It can be used for generation ( as part of ' compile ' command ) as well as
manipulation ( decoding / modifying - as part of ' disasm ' / ' asm ' commands ) of such
binary files .
Intel Compute GPU device binary is a format used by Intel Compute GPU runtime
( aka NEO ) . Intel Compute GPU runtime will return this binary format when queried
using clGetProgramInfo ( . . . , CL_PROGRAM_BINARIES , . . . ) . It will also honor
this format as input to clCreateProgramWithBinary function call .
ocloc does not require Intel GPU device to be present in the system nor does it
depend on Intel Compute GPU runtime driver to be installed . It does however rely
on the same set of compilers ( IGC , common_clang ) as the runtime driver .
Usage : ocloc [ - - help ] < command > [ < command_args > ]
Available commands are listed below .
Use ' ocloc < command > - - help ' to get help about specific command .
Commands :
compile Compiles input to Intel Compute GPU device binary .
link Links several IR files .
disasm Disassembles Intel Compute GPU device binary .
asm Assembles Intel Compute GPU device binary .
multi Compiles multiple files using a config file .
validate Validates Intel Compute GPU device binary .
query Extracts versioning info .
ids Return matching versions < major > . < minor > . < revision > .
concat Concatenates multiple fat binaries .
Default command ( when none provided ) is ' compile ' .
Examples :
Compile file to Intel Compute GPU device binary ( out = source_file_Gen9core . bin )
ocloc - file source_file . cl - device skl
Link two SPIR - V files .
ocloc link - file sample1 . spv - file sample2 . spv - out_format LLVM_BC - out samples_merged . llvm_bc
Disassemble Intel Compute GPU device binary
ocloc disasm - file source_file_Gen9core . bin
Assemble to Intel Compute GPU device binary ( after above disasm )
ocloc asm - out reassembled . bin
Validate Intel Compute GPU device binary
ocloc validate - file source_file_Gen9core . bin
Extract driver version
ocloc query OCL_DRIVER_VERSION
Return matching version for an acronym
ocloc ids dg1
Concatenate fat binaries
ocloc concat < fat binary > < fat binary > . . . [ - out < concatenated fat binary name > ]
}
) = = = " ;
2023-09-04 18:14:23 +00:00
wrapper . printf ( " %s " , help ) ;
2022-09-22 16:55:35 +00:00
}
2023-09-04 18:14:23 +00:00
void printOclocOptionsReadFromFile ( OclocArgHelper & wrapper , OfflineCompiler * pCompiler ) {
2022-09-22 16:55:35 +00:00
if ( pCompiler ) {
std : : string options = pCompiler - > getOptionsReadFromFile ( ) ;
if ( options ! = " " ) {
2023-09-04 18:14:23 +00:00
wrapper . printf ( " Compiling options read from file were: \n %s \n " , options . c_str ( ) ) ;
2022-09-22 16:55:35 +00:00
}
std : : string internalOptions = pCompiler - > getInternalOptionsReadFromFile ( ) ;
if ( internalOptions ! = " " ) {
2023-09-04 18:14:23 +00:00
wrapper . printf ( " Internal options read from file were: \n %s \n " , internalOptions . c_str ( ) ) ;
2022-09-22 16:55:35 +00:00
}
}
}
2024-08-13 13:37:03 +00:00
std : : string oclocCurrentLibName = std : : string ( NEO_OCLOC_CURRENT_LIB_NAME ) ;
std : : string oclocFormerLibName = std : : string ( NEO_OCLOC_FORMER_LIB_NAME ) ;
static_assert ( std : : string_view ( NEO_OCLOC_CURRENT_LIB_NAME ) ! = std : : string_view ( NEO_OCLOC_FORMER_LIB_NAME ) , " Ocloc current and former names cannot be same " ) ;
const std : : string & getOclocCurrentLibName ( ) { return oclocCurrentLibName ; }
const std : : string & getOclocFormerLibName ( ) { return oclocFormerLibName ; }
2022-09-22 16:55:35 +00:00
namespace Commands {
2025-10-22 23:18:58 +00:00
std : : optional < int > invokeFormerOclocWithHelper ( OclocArgHelper * argHelper ,
const std : : vector < const char * > & argvPtrs ,
uint32_t * numOutputs ,
uint8_t * * * dataOutputs ,
uint64_t * * lenOutputs ,
char * * * nameOutputs ) {
// Prepare source data arrays for former ocloc
std : : vector < const uint8_t * > dataSources ;
std : : vector < uint64_t > lenSources ;
std : : vector < const char * > nameSources ;
const auto & inputs = argHelper - > getInputs ( ) ;
dataSources . reserve ( inputs . size ( ) ) ;
lenSources . reserve ( inputs . size ( ) ) ;
nameSources . reserve ( inputs . size ( ) ) ;
for ( const auto & input : inputs ) {
dataSources . push_back ( input . data ) ;
lenSources . push_back ( input . length ) ;
nameSources . push_back ( input . name ) ;
}
// Prepare header data arrays for former ocloc
std : : vector < const uint8_t * > dataHeaders ;
std : : vector < uint64_t > lenHeaders ;
std : : vector < const char * > nameHeaders ;
const auto & headers = argHelper - > getHeaders ( ) ;
dataHeaders . reserve ( headers . size ( ) ) ;
lenHeaders . reserve ( headers . size ( ) ) ;
nameHeaders . reserve ( headers . size ( ) ) ;
for ( const auto & header : headers ) {
dataHeaders . push_back ( header . data ) ;
lenHeaders . push_back ( header . length ) ;
nameHeaders . push_back ( header . name ) ;
}
return invokeFormerOcloc ( Ocloc : : getOclocFormerLibName ( ) ,
static_cast < unsigned int > ( argvPtrs . size ( ) ) ,
const_cast < const char * * > ( argvPtrs . data ( ) ) ,
argHelper - > getNumSources ( ) ,
dataSources . empty ( ) ? nullptr : dataSources . data ( ) ,
lenSources . empty ( ) ? nullptr : lenSources . data ( ) ,
nameSources . empty ( ) ? nullptr : nameSources . data ( ) ,
argHelper - > getNumHeaders ( ) ,
dataHeaders . empty ( ) ? nullptr : dataHeaders . data ( ) ,
lenHeaders . empty ( ) ? nullptr : lenHeaders . data ( ) ,
nameHeaders . empty ( ) ? nullptr : nameHeaders . data ( ) ,
numOutputs ? numOutputs : argHelper - > getNumOutputsPtr ( ) ,
dataOutputs ? dataOutputs : argHelper - > getDataOutputsPtr ( ) ,
lenOutputs ? lenOutputs : argHelper - > getLenOutputsPtr ( ) ,
nameOutputs ? nameOutputs : argHelper - > getNameOutputsPtr ( ) ) ;
}
bool isDeviceArgProvided ( const std : : vector < std : : string > & args ) {
for ( size_t argIndex = 0 ; argIndex + 1 < args . size ( ) ; + + argIndex ) {
if ( ConstStringRef ( " -device " ) = = args [ argIndex ] ) {
return true ;
}
}
return false ;
}
2022-09-22 16:55:35 +00:00
int compile ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2024-06-27 14:44:13 +00:00
std : : vector < std : : string > argsCopy ( args ) ;
2025-10-22 23:18:58 +00:00
int deviceArgIndex = NEO : : getDeviceArgValueIdx ( args ) ;
2024-06-27 14:44:13 +00:00
2022-09-22 16:55:35 +00:00
if ( NEO : : requestedFatBinary ( args , argHelper ) ) {
2024-06-27 14:44:13 +00:00
bool onlySpirV = NEO : : isSpvOnly ( args ) ;
if ( onlySpirV ) {
2024-07-18 20:19:21 +00:00
UNRECOVERABLE_IF ( deviceArgIndex < 0 ) ;
2024-06-27 14:44:13 +00:00
std : : vector < ConstStringRef > targetProducts = NEO : : getTargetProductsForFatbinary ( ConstStringRef ( args [ deviceArgIndex ] ) , argHelper ) ;
ConstStringRef firstDevice = targetProducts . front ( ) ;
argsCopy [ deviceArgIndex ] = firstDevice . str ( ) ;
} else {
return NEO : : buildFatBinary ( args , argHelper ) ;
}
2022-09-22 16:55:35 +00:00
}
2023-09-05 17:13:13 +00:00
int retVal = OCLOC_SUCCESS ;
2025-10-22 23:18:58 +00:00
auto formerProductFallback = false ;
2022-09-22 16:55:35 +00:00
2025-10-22 23:18:58 +00:00
if ( isDeviceArgProvided ( argsCopy ) ) {
UNRECOVERABLE_IF ( deviceArgIndex < 0 ) ;
auto & formerProdHelper = * argHelper - > formerProductConfigHelper ;
auto product = formerProdHelper . getProductConfigFromDeviceName ( argsCopy [ deviceArgIndex ] ) ;
formerProductFallback = formerProdHelper . isSupportedProductConfig ( product ) ;
}
2022-09-22 16:55:35 +00:00
2025-10-22 23:18:58 +00:00
if ( formerProductFallback ) {
std : : vector < const char * > argvPtrs ;
argvPtrs . reserve ( argsCopy . size ( ) ) ;
for ( const auto & arg : argsCopy ) {
argvPtrs . push_back ( arg . c_str ( ) ) ;
2025-10-18 04:11:42 +02:00
}
2025-10-17 12:49:16 +00:00
2025-10-22 23:18:58 +00:00
auto retValFormerOcloc = invokeFormerOclocWithHelper ( argHelper , argvPtrs , nullptr , nullptr , nullptr , nullptr ) ;
if ( retValFormerOcloc ) {
retVal = retValFormerOcloc . value ( ) ;
argHelper - > dontSetupOutputs ( ) ;
2025-10-18 04:11:42 +02:00
} else {
argHelper - > printf ( " Build failed with error code: %d \n " , retVal ) ;
2025-10-17 12:49:16 +00:00
}
2025-10-22 23:18:58 +00:00
} else {
std : : unique_ptr < OfflineCompiler > pCompiler { OfflineCompiler : : create ( argsCopy . size ( ) , argsCopy , true , retVal , argHelper ) } ;
if ( retVal = = OCLOC_SUCCESS ) {
if ( pCompiler - > showHelpOnly ( ) ) {
return retVal ;
}
retVal = buildWithSafetyGuard ( pCompiler . get ( ) ) ;
2025-10-17 12:49:16 +00:00
2025-10-22 23:18:58 +00:00
std : : string buildLog = pCompiler - > getBuildLog ( ) ;
if ( buildLog . empty ( ) = = false ) {
argHelper - > printf ( " %s \n " , buildLog . c_str ( ) ) ;
}
if ( retVal = = OCLOC_SUCCESS ) {
if ( ! pCompiler - > isQuiet ( ) ) {
argHelper - > printf ( " Build succeeded. \n " ) ;
}
} else {
argHelper - > printf ( " Build failed with error code: %d \n " , retVal ) ;
}
}
if ( retVal ! = OCLOC_SUCCESS ) {
printOclocOptionsReadFromFile ( * argHelper , pCompiler . get ( ) ) ;
}
2025-10-18 04:11:42 +02:00
}
2025-10-22 23:18:58 +00:00
2022-09-22 16:55:35 +00:00
return retVal ;
} ;
int link ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-09-05 17:13:13 +00:00
int createResult { OCLOC_SUCCESS } ;
2022-09-22 16:55:35 +00:00
const auto linker { OfflineLinker : : create ( args . size ( ) , args , createResult , argHelper ) } ;
const auto linkingResult { linkWithSafetyGuard ( linker . get ( ) ) } ;
const auto buildLog = linker - > getBuildLog ( ) ;
if ( ! buildLog . empty ( ) ) {
argHelper - > printf ( " %s \n " , buildLog . c_str ( ) ) ;
}
2023-09-05 17:13:13 +00:00
if ( createResult = = OCLOC_SUCCESS & & linkingResult = = OCLOC_SUCCESS ) {
2022-09-22 16:55:35 +00:00
argHelper - > printf ( " Linker execution has succeeded! \n " ) ;
}
return createResult | linkingResult ;
} ;
int disassemble ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-02-16 15:09:51 +00:00
const auto binaryFormat = Zebin : : Manipulator : : getBinaryFormatForDisassemble ( argHelper , args ) ;
2022-08-23 15:20:14 +00:00
auto decode = [ & args ] ( auto & decoder ) - > int {
int retVal = decoder . validateInput ( args ) ;
if ( decoder . showHelp ) {
decoder . printHelp ( ) ;
2023-09-05 17:13:13 +00:00
return OCLOC_SUCCESS ;
2022-08-23 15:20:14 +00:00
}
2023-09-05 17:13:13 +00:00
return ( retVal = = OCLOC_SUCCESS ) ? decoder . decode ( ) : retVal ;
2022-08-23 15:20:14 +00:00
} ;
2022-09-22 16:55:35 +00:00
2023-02-16 15:09:51 +00:00
if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : PatchTokens ) {
2022-08-23 15:20:14 +00:00
BinaryDecoder disasm ( argHelper ) ;
return decode ( disasm ) ;
2022-09-22 16:55:35 +00:00
2023-02-16 15:09:51 +00:00
} else if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : Zebin32b ) {
Zebin : : Manipulator : : ZebinDecoder < Elf : : EI_CLASS_32 > decoder ( argHelper ) ;
2022-08-23 15:20:14 +00:00
return decode ( decoder ) ;
2022-09-22 16:55:35 +00:00
} else {
2023-02-16 15:09:51 +00:00
Zebin : : Manipulator : : ZebinDecoder < Elf : : EI_CLASS_64 > decoder ( argHelper ) ;
2022-08-23 15:20:14 +00:00
return decode ( decoder ) ;
2022-09-22 16:55:35 +00:00
}
}
int assemble ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-02-16 15:09:51 +00:00
const auto binaryFormat = Zebin : : Manipulator : : getBinaryFormatForAssemble ( argHelper , args ) ;
2022-08-23 15:20:14 +00:00
auto encode = [ & args ] ( auto & encoder ) - > int {
int retVal = encoder . validateInput ( args ) ;
if ( encoder . showHelp ) {
encoder . printHelp ( ) ;
2023-09-05 17:13:13 +00:00
return OCLOC_SUCCESS ;
2022-08-23 15:20:14 +00:00
}
2023-09-05 17:13:13 +00:00
return ( retVal = = OCLOC_SUCCESS ) ? encoder . encode ( ) : retVal ;
2022-08-23 15:20:14 +00:00
} ;
2023-02-16 15:09:51 +00:00
if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : PatchTokens ) {
2022-08-23 15:20:14 +00:00
BinaryEncoder assembler ( argHelper ) ;
return encode ( assembler ) ;
2023-02-16 15:09:51 +00:00
} else if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : Zebin32b ) {
Zebin : : Manipulator : : ZebinEncoder < Elf : : EI_CLASS_32 > encoder ( argHelper ) ;
2022-08-23 15:20:14 +00:00
return encode ( encoder ) ;
2022-09-22 16:55:35 +00:00
} else {
2023-02-16 15:09:51 +00:00
Zebin : : Manipulator : : ZebinEncoder < Elf : : EI_CLASS_64 > encoder ( argHelper ) ;
2022-08-23 15:20:14 +00:00
return encode ( encoder ) ;
2022-09-22 16:55:35 +00:00
}
}
int multi ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-09-05 17:13:13 +00:00
int retValue = OCLOC_SUCCESS ;
2022-09-22 16:55:35 +00:00
std : : unique_ptr < MultiCommand > pMulti { ( MultiCommand : : create ( args , retValue , argHelper ) ) } ;
return retValue ;
}
int validate ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
return Ocloc : : validate ( args , argHelper ) ;
}
int query ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
return OfflineCompiler : : query ( args . size ( ) , args , argHelper ) ;
}
int ids ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
return OfflineCompiler : : queryAcronymIds ( args . size ( ) , args , argHelper ) ;
}
int concat ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
auto arConcat = NEO : : OclocConcat ( argHelper ) ;
auto error = arConcat . initialize ( args ) ;
2023-09-05 17:13:13 +00:00
if ( OCLOC_SUCCESS ! = error ) {
2022-09-22 16:55:35 +00:00
arConcat . printHelp ( ) ;
return error ;
}
error = arConcat . concatenate ( ) ;
return error ;
}
2024-08-13 15:26:18 +00:00
std : : optional < int > invokeFormerOcloc ( const std : : string & formerOclocName , unsigned int numArgs , const char * argv [ ] ,
const uint32_t numSources , const uint8_t * * dataSources , const uint64_t * lenSources , const char * * nameSources ,
const uint32_t numInputHeaders , const uint8_t * * dataInputHeaders , const uint64_t * lenInputHeaders , const char * * nameInputHeaders ,
uint32_t * numOutputs , uint8_t * * * dataOutputs , uint64_t * * lenOutputs , char * * * nameOutputs ) {
if ( formerOclocName . empty ( ) ) {
return { } ;
}
2024-08-19 12:50:05 +00:00
std : : unique_ptr < OsLibrary > oclocLib ( OsLibrary : : loadFunc ( formerOclocName ) ) ;
2024-08-13 15:26:18 +00:00
2024-08-20 12:51:06 +00:00
if ( ! oclocLib ) {
2024-08-13 15:26:18 +00:00
return { } ;
}
auto oclocInvokeFunc = reinterpret_cast < pOclocInvoke > ( oclocLib - > getProcAddress ( " oclocInvoke " ) ) ;
return oclocInvokeFunc ( numArgs , argv , numSources , dataSources , lenSources , nameSources , numInputHeaders , dataInputHeaders , lenInputHeaders , nameInputHeaders , numOutputs , dataOutputs , lenOutputs , nameOutputs ) ;
}
2022-09-22 16:55:35 +00:00
2025-10-22 23:18:58 +00:00
std : : optional < int > formerOclocFree ( const std : : string & formerOclocName , uint32_t * numOutputs , uint8_t * * * dataOutputs , uint64_t * * lenOutputs , char * * * nameOutputs ) {
if ( formerOclocName . empty ( ) ) {
return { } ;
}
std : : unique_ptr < OsLibrary > oclocLib ( OsLibrary : : loadFunc ( formerOclocName ) ) ;
if ( ! oclocLib ) {
return { } ;
}
typedef int ( * pOclocFreeOutput ) ( uint32_t * numOutputs , uint8_t * * * dataOutputs , uint64_t * * lenOutputs , char * * * nameOutputs ) ;
auto oclocFreeFunc = reinterpret_cast < pOclocFreeOutput > ( oclocLib - > getProcAddress ( " oclocFreeOutput " ) ) ;
if ( ! oclocFreeFunc ) {
return { } ;
}
return oclocFreeFunc ( numOutputs , dataOutputs , lenOutputs , nameOutputs ) ;
}
2022-09-22 16:55:35 +00:00
} // namespace Commands
} // namespace Ocloc