2022-09-23 00:55:35 +08:00
/*
2024-01-24 21:24:34 +08:00
* Copyright ( C ) 2022 - 2024 Intel Corporation
2022-09-23 00:55:35 +08: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 23:20:14 +08:00
# include "shared/offline_compiler/source/decoder/zebin_manipulator.h"
2022-09-23 00:55:35 +08:00
# include "shared/offline_compiler/source/multi_command.h"
2023-09-06 01:13:13 +08:00
# include "shared/offline_compiler/source/ocloc_api.h"
2022-09-23 00:55:35 +08: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 23:20:14 +08:00
# include "shared/source/device_binary_format/elf/elf_decoder.h"
2024-08-13 23:26:18 +08:00
# include "shared/source/os_interface/os_library.h"
2022-09-23 00:55:35 +08:00
# include <memory>
namespace Ocloc {
using namespace NEO ;
2023-09-05 02:14:23 +08:00
void printOclocCmdLine ( OclocArgHelper & wrapper , const std : : vector < std : : string > & args ) {
2022-09-23 00:55:35 +08:00
auto areQuotesRequired = [ ] ( const std : : string_view & argName ) - > bool {
return argName = = " -options " | | argName = = " -internal_options " ;
} ;
2023-09-05 02:14:23 +08:00
wrapper . printf ( " Command was: " ) ;
2022-09-23 00:55:35 +08:00
bool useQuotes = false ;
for ( auto & currArg : args ) {
if ( useQuotes ) {
2023-09-05 02:14:23 +08:00
wrapper . printf ( " \" %s \" " , currArg . c_str ( ) ) ;
2022-09-23 00:55:35 +08:00
useQuotes = false ;
} else {
2023-09-05 02:14:23 +08:00
wrapper . printf ( " %s " , currArg . c_str ( ) ) ;
2022-09-23 00:55:35 +08:00
useQuotes = areQuotesRequired ( currArg . c_str ( ) ) ;
}
}
2023-09-05 02:14:23 +08:00
wrapper . printf ( " \n " ) ;
2022-09-23 00:55:35 +08:00
}
2023-09-05 02:14:23 +08:00
void printHelp ( OclocArgHelper & wrapper ) {
2022-09-23 00:55:35 +08: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-05 02:14:23 +08:00
wrapper . printf ( " %s " , help ) ;
2022-09-23 00:55:35 +08:00
}
2023-09-05 02:14:23 +08:00
void printOclocOptionsReadFromFile ( OclocArgHelper & wrapper , OfflineCompiler * pCompiler ) {
2022-09-23 00:55:35 +08:00
if ( pCompiler ) {
std : : string options = pCompiler - > getOptionsReadFromFile ( ) ;
if ( options ! = " " ) {
2023-09-05 02:14:23 +08:00
wrapper . printf ( " Compiling options read from file were: \n %s \n " , options . c_str ( ) ) ;
2022-09-23 00:55:35 +08:00
}
std : : string internalOptions = pCompiler - > getInternalOptionsReadFromFile ( ) ;
if ( internalOptions ! = " " ) {
2023-09-05 02:14:23 +08:00
wrapper . printf ( " Internal options read from file were: \n %s \n " , internalOptions . c_str ( ) ) ;
2022-09-23 00:55:35 +08:00
}
}
}
2024-08-13 21:37:03 +08: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-23 00:55:35 +08:00
namespace Commands {
int compile ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2024-06-27 22:44:13 +08:00
std : : vector < std : : string > argsCopy ( args ) ;
2022-09-23 00:55:35 +08:00
if ( NEO : : requestedFatBinary ( args , argHelper ) ) {
2024-06-27 22:44:13 +08:00
bool onlySpirV = NEO : : isSpvOnly ( args ) ;
if ( onlySpirV ) {
int deviceArgIndex = NEO : : getDeviceArgValueIdx ( args ) ;
2024-07-19 04:19:21 +08:00
UNRECOVERABLE_IF ( deviceArgIndex < 0 ) ;
2024-06-27 22:44:13 +08: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-23 00:55:35 +08:00
}
2023-09-06 01:13:13 +08:00
int retVal = OCLOC_SUCCESS ;
2024-06-27 22:44:13 +08:00
std : : unique_ptr < OfflineCompiler > pCompiler { OfflineCompiler : : create ( argsCopy . size ( ) , argsCopy , true , retVal , argHelper ) } ;
2022-09-23 00:55:35 +08:00
2023-09-06 01:13:13 +08:00
if ( retVal = = OCLOC_SUCCESS ) {
2023-03-06 17:01:46 +08:00
if ( pCompiler - > showHelpOnly ( ) ) {
return retVal ;
}
2022-09-23 00:55:35 +08:00
retVal = buildWithSafetyGuard ( pCompiler . get ( ) ) ;
std : : string buildLog = pCompiler - > getBuildLog ( ) ;
if ( buildLog . empty ( ) = = false ) {
argHelper - > printf ( " %s \n " , buildLog . c_str ( ) ) ;
}
2023-09-06 01:13:13 +08:00
if ( retVal = = OCLOC_SUCCESS ) {
2022-09-23 00:55:35 +08:00
if ( ! pCompiler - > isQuiet ( ) )
argHelper - > printf ( " Build succeeded. \n " ) ;
} else {
argHelper - > printf ( " Build failed with error code: %d \n " , retVal ) ;
}
}
2023-09-06 01:13:13 +08:00
if ( retVal ! = OCLOC_SUCCESS ) {
2023-09-05 02:14:23 +08:00
printOclocOptionsReadFromFile ( * argHelper , pCompiler . get ( ) ) ;
2022-09-23 00:55:35 +08:00
}
return retVal ;
} ;
int link ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-09-06 01:13:13 +08:00
int createResult { OCLOC_SUCCESS } ;
2022-09-23 00:55:35 +08: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-06 01:13:13 +08:00
if ( createResult = = OCLOC_SUCCESS & & linkingResult = = OCLOC_SUCCESS ) {
2022-09-23 00:55:35 +08:00
argHelper - > printf ( " Linker execution has succeeded! \n " ) ;
}
return createResult | linkingResult ;
} ;
int disassemble ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-02-16 23:09:51 +08:00
const auto binaryFormat = Zebin : : Manipulator : : getBinaryFormatForDisassemble ( argHelper , args ) ;
2022-08-23 23:20:14 +08:00
auto decode = [ & args ] ( auto & decoder ) - > int {
int retVal = decoder . validateInput ( args ) ;
if ( decoder . showHelp ) {
decoder . printHelp ( ) ;
2023-09-06 01:13:13 +08:00
return OCLOC_SUCCESS ;
2022-08-23 23:20:14 +08:00
}
2023-09-06 01:13:13 +08:00
return ( retVal = = OCLOC_SUCCESS ) ? decoder . decode ( ) : retVal ;
2022-08-23 23:20:14 +08:00
} ;
2022-09-23 00:55:35 +08:00
2023-02-16 23:09:51 +08:00
if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : PatchTokens ) {
2022-08-23 23:20:14 +08:00
BinaryDecoder disasm ( argHelper ) ;
return decode ( disasm ) ;
2022-09-23 00:55:35 +08:00
2023-02-16 23:09:51 +08:00
} else if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : Zebin32b ) {
Zebin : : Manipulator : : ZebinDecoder < Elf : : EI_CLASS_32 > decoder ( argHelper ) ;
2022-08-23 23:20:14 +08:00
return decode ( decoder ) ;
2022-09-23 00:55:35 +08:00
} else {
2023-02-16 23:09:51 +08:00
Zebin : : Manipulator : : ZebinDecoder < Elf : : EI_CLASS_64 > decoder ( argHelper ) ;
2022-08-23 23:20:14 +08:00
return decode ( decoder ) ;
2022-09-23 00:55:35 +08:00
}
}
int assemble ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-02-16 23:09:51 +08:00
const auto binaryFormat = Zebin : : Manipulator : : getBinaryFormatForAssemble ( argHelper , args ) ;
2022-08-23 23:20:14 +08:00
auto encode = [ & args ] ( auto & encoder ) - > int {
int retVal = encoder . validateInput ( args ) ;
if ( encoder . showHelp ) {
encoder . printHelp ( ) ;
2023-09-06 01:13:13 +08:00
return OCLOC_SUCCESS ;
2022-08-23 23:20:14 +08:00
}
2023-09-06 01:13:13 +08:00
return ( retVal = = OCLOC_SUCCESS ) ? encoder . encode ( ) : retVal ;
2022-08-23 23:20:14 +08:00
} ;
2023-02-16 23:09:51 +08:00
if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : PatchTokens ) {
2022-08-23 23:20:14 +08:00
BinaryEncoder assembler ( argHelper ) ;
return encode ( assembler ) ;
2023-02-16 23:09:51 +08:00
} else if ( binaryFormat = = Zebin : : Manipulator : : BinaryFormats : : Zebin32b ) {
Zebin : : Manipulator : : ZebinEncoder < Elf : : EI_CLASS_32 > encoder ( argHelper ) ;
2022-08-23 23:20:14 +08:00
return encode ( encoder ) ;
2022-09-23 00:55:35 +08:00
} else {
2023-02-16 23:09:51 +08:00
Zebin : : Manipulator : : ZebinEncoder < Elf : : EI_CLASS_64 > encoder ( argHelper ) ;
2022-08-23 23:20:14 +08:00
return encode ( encoder ) ;
2022-09-23 00:55:35 +08:00
}
}
int multi ( OclocArgHelper * argHelper , const std : : vector < std : : string > & args ) {
2023-09-06 01:13:13 +08:00
int retValue = OCLOC_SUCCESS ;
2022-09-23 00:55:35 +08: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-06 01:13:13 +08:00
if ( OCLOC_SUCCESS ! = error ) {
2022-09-23 00:55:35 +08:00
arConcat . printHelp ( ) ;
return error ;
}
error = arConcat . concatenate ( ) ;
return error ;
}
2024-08-13 23:26:18 +08: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 20:50:05 +08:00
std : : unique_ptr < OsLibrary > oclocLib ( OsLibrary : : loadFunc ( formerOclocName ) ) ;
2024-08-13 23:26:18 +08:00
2024-08-20 20:51:06 +08:00
if ( ! oclocLib ) {
2024-08-13 23:26:18 +08: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-23 00:55:35 +08:00
} // namespace Commands
} // namespace Ocloc