diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 70e849d37986a..7926b8edd5821 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -10097,8 +10097,13 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, // clang-offload-wrapper // -o=.bc // -host=x86_64-pc-linux-gnu -kind=sycl +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES // -format=spirv .spv (optional) // -format=spirv .spv (optional) +#else + // -format=spirv .spv + // -format=spirv .spv +#endif // ... ArgStringList WrapperArgs; @@ -10163,6 +10168,12 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, WrapperArgs.push_back( C.getArgs().MakeArgString(Twine("-kind=") + Twine(Kind))); + // Enable preview breaking changes in clang-offload-wrapper, + // in case it needs to introduce any ABI breaking changes. + // For example, changes in offload binary descriptor format. + if (C.getArgs().hasArg(options::OPT_fpreview_breaking_changes)) + WrapperArgs.push_back("-fpreview-breaking-changes"); + assert((Inputs.size() > 0) && "no inputs for clang-offload-wrapper"); assert(((Inputs[0].getType() != types::TY_Tempfiletable) || (Inputs.size() == 1)) && @@ -11580,6 +11591,12 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString("--wrapper-jobs=" + Twine(NumThreads))); } + // Enable preview breaking changes in clang-linker-wrapper, + // in case it needs to introduce any ABI breaking changes. + // For example, changes in offload binary descriptor format. + if (Args.hasArg(options::OPT_fpreview_breaking_changes)) + CmdArgs.push_back("-fpreview-breaking-changes"); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper")); diff --git a/clang/test/Driver/clang-offload-wrapper-exe-preview.cpp b/clang/test/Driver/clang-offload-wrapper-exe-preview.cpp new file mode 100644 index 0000000000000..5524e873f1c90 --- /dev/null +++ b/clang/test/Driver/clang-offload-wrapper-exe-preview.cpp @@ -0,0 +1,235 @@ +// End-to-end test for clang-offload-wrapper executable: +// Verifies that the clang-offload-wrapper's -batch option correctly processes +// multiple device binaries: +// Test creates two device binary images with associated properties and symbols, +// and a batch input file describing them [1, 1a, 1b, 2]. +// It also creates the expected "gold" output for the first image, +// by concatenating the input data [3]. +// It then runs clang-offload-wrapper to generate the expected wrapper object, +// and batch file created on step [2] is passed as an input to +// clang-offload-wrapper to produce device binary descriptors for each of the +// wrapped images. Resulting .bc file is compiled with llc to produce an +// object file [4]. +// Then the test is compiled and linked with the generated wrapper object [5]. +// Finally, the test executable is run and its output is compared to the "gold" +// output created on step [3], ignoring white spaces [6]. +// Expected behavior is that the clang-offload-wrapper correctly encodes +// the input data for multiple device binaries described in input batch file +// and that the resulting runtime data +// (device code, properties, and symbols) is accessible and matches the input. +// The test checks both integer and byte array property values, ensuring proper +// decoding and runtime access. + +// [1] Prepare test data. +// [1a] Create the first binary image. +// RUN: echo -e -n 'device binary image1\n' > %t.bin +// RUN: echo -e -n '[Category1]\nint_prop1=1|10\n[Category2]\nint_prop2=1|20\n' > %t.props +// RUN: echo -e -n 'kernel1\nkernel2\n' > %t.sym + +// [1b] Create the second binary image with byte array property values. +// RUN: echo -e -n 'device binary image2\n' > %t_1.bin +// RUN: echo -e -n '[Category3]\n' > %t_1.props +// RUN: echo -e -n 'kernel1=2|IAAAAAAAAAQA\n' >> %t_1.props +// RUN: echo -e -n 'kernel2=2|oAAAAAAAAAw///3/wB\n' >> %t_1.props + +// [2] Create the batch file input for the wrapper. +// RUN: echo '[Code|Properties|Symbols]' > %t.batch +// RUN: echo %t.bin"|"%t.props"|"%t.sym >> %t.batch +// RUN: echo %t_1.bin"|"%t_1.props"|" >> %t.batch + +// [3] Generate "gold" output. "gold" output is the concatenation of all input +// data, in the order it is expected to be outputed by the test, +// see `dumpBinary0` below. +// After test is run on step [6], `dumpBinary0` outputs binary image data and +// this output is compared to the "gold" output. +// RUN: cat %t.bin %t.props %t.sym > %t.all + +// [4] Create the wrapper object. +#ifdef __INTEL_PREVIEW_BREAKING_CHANGES +/// TODO: Remove -fpreview-breaking-changes from the command line, when removing the macro. +// RUN: clang-offload-wrapper -kind=sycl -target=TARGET -format=native -batch %t.batch -o %t.wrapped.bc -fpreview-breaking-changes +#endif // __INTEL_PREVIEW_BREAKING_CHANGES +// RUN: llc --filetype=obj %t.wrapped.bc -o %t.wrapped.o + +// [5] Compile & link the test with the wrapper. +// RUN: %clangxx %t.wrapped.o %s -o %t.batch.exe + +// [6] Run and check ignoring white spaces. +// RUN: %t.batch.exe > %t.batch.exe.out +// RUN: diff -b %t.batch.exe.out %t.all + +#include +#include +#include +#include + +// Data types created by the offload wrapper and inserted in the wrapper object. +// Matches those defined in SYCL Runtime. +struct _sycl_offload_entry_struct { + void *addr; + char *name; + size_t size; + int32_t flags; + int32_t reserved; +}; + +typedef _sycl_offload_entry_struct *_sycl_offload_entry; + +struct _sycl_device_binary_property_struct { + char *Name; // Null-terminated property name. + void *ValAddr; // Address of property value. + uint32_t Type; // pi_property_type. + uint64_t ValSize; // Size of property value in bytes. +}; + +typedef _sycl_device_binary_property_struct *sycl_device_binary_property; + +struct _sycl_device_binary_property_set_struct { + char *Name; // The name. + sycl_device_binary_property PropertiesBegin; // Array start. + sycl_device_binary_property PropertiesEnd; // Array end. +}; + +typedef _sycl_device_binary_property_set_struct *sycl_device_binary_property_set; + +struct sycl_device_binary_struct { + uint16_t Version; + uint8_t Kind; // Type of offload model the binary employs; must be 4 for SYCL. + uint8_t Format; // Format of the binary data: SPIR-V, LLVM IR bitcode, ... + const char *DeviceTargetSpec; + const char *CompileOptions; + const char *LinkOptions; + const unsigned char *BinaryStart; + const unsigned char *BinaryEnd; + _sycl_offload_entry EntriesBegin; + _sycl_offload_entry EntriesEnd; + sycl_device_binary_property_set PropertySetsBegin; + sycl_device_binary_property_set PropertySetsEnd; +}; +typedef sycl_device_binary_struct *sycl_device_binary; + +struct sycl_device_binaries_struct { + uint16_t Version; + uint16_t NumDeviceBinaries; + sycl_device_binary DeviceBinaries; + _sycl_offload_entry *HostEntriesBegin; + _sycl_offload_entry *HostEntriesEnd; +}; +typedef sycl_device_binaries_struct *sycl_device_binaries; + +static sycl_device_binaries BinDesc = nullptr; + +// Wrapper object has code which calls these 2 functions below. +extern "C" void __sycl_register_lib(sycl_device_binaries desc) { + BinDesc = desc; +} + +extern "C" void __sycl_unregister_lib() {} + +#define ASSERT(Cond, Msg) \ + if (!(Cond)) { \ + std::cerr << "*** ERROR: wrong " << Msg << "\n"; \ + return 1; \ + } + +static std::string getString(const unsigned char *B, const unsigned char *E) { + return std::string(reinterpret_cast(B), E - B); +} + +static int getInt(void *Addr) { + const char *Ptr = reinterpret_cast(Addr); + return Ptr[0] | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24); +} + +using byte = unsigned char; + +static void printProp(const sycl_device_binary_property &Prop) { + std::cerr << "Property " << Prop->Name << " {\n"; + std::cerr << " Type: " << Prop->Type << "\n"; + if (Prop->Type != 1) + std::cerr << " Size = " << Prop->ValSize << "\n"; + + std::cerr << " Value = "; + if (Prop->Type == 1) + std::cerr << getInt(&Prop->ValSize); + else { + std::cerr << " {\n "; + + byte *Ptr = (byte *)Prop->ValAddr; + + for (auto I = 0; I < Prop->ValSize && I < 100; ++I) { + std::cerr << " 0x" << std::hex << (unsigned int)Ptr[I]; + std::cerr << std::dec; + } + std::cerr << "\n }"; + } + std::cerr << "\n"; + std::cerr << "}\n"; +} + +static int dumpBinary0() { + sycl_device_binary Bin = &BinDesc->DeviceBinaries[0]; + ASSERT(Bin->Kind == 4, "Bin->Kind"); + ASSERT(Bin->Format == 1, "Bin->Format"); + + // Dump code. + std::cout << getString(Bin->BinaryStart, Bin->BinaryEnd); + // Dump properties. + for (sycl_device_binary_property_set PropSet = Bin->PropertySetsBegin; PropSet != Bin->PropertySetsEnd; ++PropSet) { + std::cout << "[" << PropSet->Name << "]" + << "\n"; + + for (sycl_device_binary_property Prop = PropSet->PropertiesBegin; Prop != PropSet->PropertiesEnd; ++Prop) { + ASSERT(Prop->Type == 1, "Prop->Type"); + std::cout << Prop->Name << "=" << Prop->Type << "|" << getInt(&Prop->ValSize) << "\n"; + } + } + // Dump symbols. + for (_sycl_offload_entry Entry = Bin->EntriesBegin; Entry != Bin->EntriesEnd; ++Entry) + std::cout << Entry->name << "\n"; + return 0; +} + +// Clang offload wrapper does Base64 decoding on byte array property values, so +// they can't be dumped as is and compared to the original. Instead, this +// testcase checks that the byte array in the property value is equal to the +// pre-decoded byte array. +static int checkBinary1() { + // Decoded from "IAAAAAAAAAQA": + const byte Arr0[] = {8, 0, 0, 0, 0, 0, 0, 0, 0x1}; + // Decoded from "oAAAAAAAAAw///3/wB": + const byte Arr1[] = {40, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0x7F, 0xFF, 0x70}; + + struct { + const byte *Ptr; + const size_t Size; + } GoldArrays[] = { + {Arr0, sizeof(Arr0)}, + {Arr1, sizeof(Arr1)}}; + sycl_device_binary Bin = &BinDesc->DeviceBinaries[1]; + ASSERT(Bin->Kind == 4, "Bin->Kind"); + ASSERT(Bin->Format == 1, "Bin->Format"); + + for (sycl_device_binary_property_set PropSet = Bin->PropertySetsBegin; PropSet != Bin->PropertySetsEnd; ++PropSet) { + int Cnt = 0; + + for (sycl_device_binary_property Prop = PropSet->PropertiesBegin; Prop != PropSet->PropertiesEnd; ++Prop, ++Cnt) { + ASSERT(Prop->Type == 2, "Prop->Type"); // Must be a byte array. + char *Ptr = reinterpret_cast(Prop->ValAddr); + int Cmp = std::memcmp(Prop->ValAddr, GoldArrays[Cnt].Ptr, GoldArrays[Cnt].Size); + ASSERT(Cmp == 0, "byte array property"); + } + } + return 0; +} + +int main(int argc, char **argv) { + ASSERT(BinDesc->NumDeviceBinaries == 2, "BinDesc->NumDeviceBinaries"); + ASSERT(BinDesc->Version == 1, "BinDesc->Version"); + + if (dumpBinary0() != 0) + return 1; + if (checkBinary1() != 0) + return 1; + return 0; +} diff --git a/clang/test/Driver/clang-offload-wrapper-exe.cpp b/clang/test/Driver/clang-offload-wrapper-exe.cpp index 668e68874115a..6af0a7d2c7250 100644 --- a/clang/test/Driver/clang-offload-wrapper-exe.cpp +++ b/clang/test/Driver/clang-offload-wrapper-exe.cpp @@ -3,6 +3,11 @@ // End-to-end clang-offload-wrapper executable test: check that -batch options // works, and that the tool generates data properly accessible at runtime. +#ifdef __INTEL_PREVIEW_BREAKING_CHANGES +/// TODO: Delete this test when the preview changes are enabled by default. +/// Rename clang-offload-wrapper-exe-preview.cpp to clang-offload-wrapper-exe.cpp +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + // --- Prepare test data // - create the first binary image // RUN: echo -e -n 'device binary image1\n' > %t.bin diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 03f61c6ea195d..f481bdab82ebc 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -303,7 +303,6 @@ Expected writeOffloadFile(const OffloadFile &File, StringRef Prefix = sys::path::stem(Binary.getMemoryBufferRef().getBufferIdentifier()); - StringRef Suffix = getImageKindName(Binary.getImageKind()); StringRef BinArch = (Binary.getArch() == "*") ? "any" : Binary.getArch(); auto TempFileOrErr = createOutputFile( @@ -1129,7 +1128,9 @@ wrapSYCLBinariesFromFile(std::vector &SplitModules, errs() << formatv(" offload-wrapper: compile-opts: {0}, link-opts: {1}\n", CompileOptions, LinkOptions); } - if (Error E = offloading::wrapSYCLBinaries(M, Images, WrappingOptions)) + if (Error E = offloading::wrapSYCLBinaries( + M, Images, WrappingOptions, + Args.hasArg(OPT_preview_breaking_changes))) return E; if (Args.hasArg(OPT_print_wrapped_module)) diff --git a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td index 7e7e026a47e82..1e7cd060278cb 100644 --- a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td +++ b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td @@ -73,6 +73,10 @@ def should_extract : CommaJoined<["--"], "should-extract=">, Flags<[WrapperOnlyOption]>, MetaVarName<"">, HelpText<"Set of device architectures we should always extract if found.">; +def preview_breaking_changes : Flag<["-"], "fpreview-breaking-changes">, + Flags<[WrapperOnlyOption]>, + HelpText<"Enables preview of breaking changes in the wrapper">; + // Flags passed to the device linker. def arch_EQ : Joined<["--"], "arch=">, Flags<[DeviceOnlyOption, HelpHidden]>, MetaVarName<"">, diff --git a/clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp b/clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp index bb18a7214fd3f..4814ef05b1561 100644 --- a/clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp +++ b/clang/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp @@ -81,7 +81,9 @@ using namespace llvm::object; static constexpr char COL_CODE[] = "Code"; static constexpr char COL_SYM[] = "Symbols"; static constexpr char COL_PROPS[] = "Properties"; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES static constexpr char COL_MANIFEST[] = "Manifest"; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // Offload models supported by this tool. The support basically means mapping // a string representation given at the command line to a value from this @@ -118,6 +120,11 @@ template <> struct DenseMapInfo { static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); +static cl::opt + PreviewBreakingChanges("fpreview-breaking-changes", + cl::desc("Enable preview breaking changes"), + cl::init(false), cl::Hidden); + // Mark all our options with this category, everything else (except for -version // and -help) will be hidden. static cl::OptionCategory @@ -250,8 +257,13 @@ static cl::opt BatchMode( "Table files consist of a table of filenames that provide\n" "Code, Symbols, Properties, etc.\n" "Example input table file in batch mode:\n" +#ifdef __INTEL_PREVIEW_BREAKING_CHANGES + " [Code|Symbols|Properties]\n" + " a_0.bc|a_0.sym|a_0.props\n" +#else " [Code|Symbols|Properties|Manifest]\n" " a_0.bc|a_0.sym|a_0.props|a_0.mnf\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES " a_1.bin|||\n" "Example usage:\n" " clang-offload-wrapper -batch -host=x86_64-unknown-linux-gnu\n" @@ -315,6 +327,7 @@ class BinaryWrapper { /// Represents a single image to wrap. class Image { public: +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES Image(const llvm::StringRef File_, const llvm::StringRef Manif_, const llvm::StringRef Tgt_, BinaryImageFormat Fmt_, const llvm::StringRef CompileOpts_, const llvm::StringRef LinkOpts_, @@ -322,11 +335,21 @@ class BinaryWrapper { : File(File_.str()), Manif(Manif_.str()), Tgt(Tgt_.str()), Fmt(Fmt_), CompileOpts(CompileOpts_.str()), LinkOpts(LinkOpts_.str()), EntriesFile(EntriesFile_.str()), PropsFile(PropsFile_.str()) {} +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + Image(const llvm::StringRef File_, const llvm::StringRef Tgt_, + BinaryImageFormat Fmt_, const llvm::StringRef CompileOpts_, + const llvm::StringRef LinkOpts_, const llvm::StringRef EntriesFile_, + const llvm::StringRef PropsFile_) + : File(File_.str()), Tgt(Tgt_.str()), Fmt(Fmt_), + CompileOpts(CompileOpts_.str()), LinkOpts(LinkOpts_.str()), + EntriesFile(EntriesFile_.str()), PropsFile(PropsFile_.str()) {} /// Name of the file with actual contents const std::string File; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES /// Name of the manifest file const std::string Manif; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES /// Offload target architecture const std::string Tgt; /// Format @@ -368,6 +391,7 @@ class BinaryWrapper { llvm::SmallVector, 4> AutoGcBufs; public: +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES void addImage(const OffloadKind Kind, llvm::StringRef File, llvm::StringRef Manif, llvm::StringRef Tgt, const BinaryImageFormat Fmt, llvm::StringRef CompileOpts, @@ -379,6 +403,17 @@ class BinaryWrapper { Pack->emplace_back(std::make_unique( File, Manif, Tgt, Fmt, CompileOpts, LinkOpts, EntriesFile, PropsFile)); } +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + void addImage(const OffloadKind Kind, llvm::StringRef File, + llvm::StringRef Tgt, const BinaryImageFormat Fmt, + llvm::StringRef CompileOpts, llvm::StringRef LinkOpts, + llvm::StringRef EntriesFile, llvm::StringRef PropsFile) { + std::unique_ptr &Pack = Packs[Kind]; + if (!Pack) + Pack.reset(new SameKindPack()); + Pack->emplace_back(std::make_unique( + File, Tgt, Fmt, CompileOpts, LinkOpts, EntriesFile, PropsFile)); + } std::string ToolName; std::string ObjcopyPath; @@ -474,9 +509,14 @@ class BinaryWrapper { return DescTy; } - // DeviceImageStructVersion change log: - // -- version 2: updated to PI 1.2 binary image format +// DeviceImageStructVersion change log: +// -- version 2: updated to PI 1.2 binary image format +// -- version 3: removed ManifestStart, ManifestEnd pointers +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES const uint16_t DeviceImageStructVersion = 2; +#else + const uint16_t DeviceImageStructVersion = 3; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // typedef enum { // PI_PROPERTY_TYPE_INT32, @@ -542,10 +582,12 @@ class BinaryWrapper { // /// a null-terminated string; target- and compiler-specific options // /// which are suggested to use to "link" program at runtime // const char *LinkOptions; - // /// Pointer to the manifest data start - // const unsigned char *ManifestStart; - // /// Pointer to the manifest data end - // const unsigned char *ManifestEnd; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES +// /// Pointer to the manifest data start +// const unsigned char *ManifestStart; +// /// Pointer to the manifest data end +// const unsigned char *ManifestEnd; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // /// Pointer to the device binary image start // void *ImageStart; // /// Pointer to the device binary image end @@ -560,24 +602,47 @@ class BinaryWrapper { StructType *getSyclDeviceImageTy() { if (!SyclImageTy) { - SyclImageTy = StructType::create( - { - Type::getInt16Ty(C), // Version - Type::getInt8Ty(C), // OffloadKind - Type::getInt8Ty(C), // Format - getPtrTy(), // DeviceTargetSpec - getPtrTy(), // CompileOptions - getPtrTy(), // LinkOptions - getPtrTy(), // ManifestStart - getPtrTy(), // ManifestEnd - getPtrTy(), // ImageStart - getPtrTy(), // ImageEnd - getPtrTy(), // EntriesBegin - getPtrTy(), // EntriesEnd - getPtrTy(), // PropertySetBegin - getPtrTy() // PropertySetEnd - }, - "__tgt_device_image"); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + if (!PreviewBreakingChanges) { + SyclImageTy = StructType::create( + { + Type::getInt16Ty(C), // Version + Type::getInt8Ty(C), // OffloadKind + Type::getInt8Ty(C), // Format + getPtrTy(), // DeviceTargetSpec + getPtrTy(), // CompileOptions + getPtrTy(), // LinkOptions + getPtrTy(), // ManifestStart + getPtrTy(), // ManifestEnd + getPtrTy(), // ImageStart + getPtrTy(), // ImageEnd + getPtrTy(), // EntriesBegin + getPtrTy(), // EntriesEnd + getPtrTy(), // PropertySetBegin + getPtrTy() // PropertySetEnd + }, + "__tgt_device_image"); + } else { +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + SyclImageTy = StructType::create( + { + Type::getInt16Ty(C), // Version + Type::getInt8Ty(C), // OffloadKind + Type::getInt8Ty(C), // Format + getPtrTy(), // DeviceTargetSpec + getPtrTy(), // CompileOptions + getPtrTy(), // LinkOptions + getPtrTy(), // ImageStart + getPtrTy(), // ImageEnd + getPtrTy(), // EntriesBegin + getPtrTy(), // EntriesEnd + getPtrTy(), // PropertySetBegin + getPtrTy() // PropertySetEnd + }, + "__tgt_device_image"); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + } +#endif // __INTEL_PREVIEW_BREAKING_CHANGES } return SyclImageTy; } @@ -1018,7 +1083,9 @@ class BinaryWrapper { } auto *Zero = ConstantInt::get(getSizeTTy(), 0u); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES auto *NullPtr = Constant::getNullValue(getPtrTy()); +#endif // __INTEL_PREVIEW_BREAKING_CHANGES Constant *ZeroZero[] = {Zero, Zero}; // Create initializer for the images array. @@ -1030,8 +1097,14 @@ class BinaryWrapper { if (Verbose) errs() << "adding image: offload kind=" << offloadKindToString(Kind) << Img << "\n"; - auto *Fver = - ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion); + + auto *Fver = ConstantInt::get( + Type::getInt16Ty(C), +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + PreviewBreakingChanges ? 3 : DeviceImageStructVersion); +#else + DeviceImageStructVersion); +#endif // __INTEL_PREVIEW_BREAKING_CHANGES auto *Fknd = ConstantInt::get(Type::getInt8Ty(C), Kind); auto *Ffmt = ConstantInt::get(Type::getInt8Ty(C), Img.Fmt); auto *Ftgt = addStringToModule( @@ -1042,24 +1115,29 @@ class BinaryWrapper { auto *Foptlink = addStringToModule(Img.LinkOpts, Twine(OffloadKindTag) + Twine("opts.link.") + Twine(ImgId)); + +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES std::pair FMnf; + if (!PreviewBreakingChanges) { + if (Img.Manif.empty()) { + // No manifest - zero out the fields. + FMnf = std::make_pair(NullPtr, NullPtr); + } else { + Expected MnfOrErr = loadFile(Img.Manif); + if (!MnfOrErr) + return MnfOrErr.takeError(); + MemoryBuffer *Mnf = *MnfOrErr; + FMnf = addArrayToModule( + ArrayRef(Mnf->getBufferStart(), Mnf->getBufferSize()), + Twine(OffloadKindTag) + Twine(ImgId) + Twine(".manifest")); + } + } +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + if (MySymPropReader) MySymPropReader->getNextDeviceImageInitializer(); - if (Img.Manif.empty()) { - // no manifest - zero out the fields - FMnf = std::make_pair(NullPtr, NullPtr); - } else { - Expected MnfOrErr = loadFile(Img.Manif); - if (!MnfOrErr) - return MnfOrErr.takeError(); - MemoryBuffer *Mnf = *MnfOrErr; - FMnf = addArrayToModule( - ArrayRef(Mnf->getBufferStart(), Mnf->getBufferSize()), - Twine(OffloadKindTag) + Twine(ImgId) + Twine(".manifest")); - } - Expected> PropSets = tformSYCLPropertySetRegistryFileToIR(Img.PropsFile); if (!PropSets) @@ -1158,11 +1236,25 @@ class BinaryWrapper { if (!EntriesOrErr) return EntriesOrErr.takeError(); std::pair ImageEntriesPtrs = *EntriesOrErr; - ImagesInits.push_back(ConstantStruct::get( - getSyclDeviceImageTy(), Fver, Fknd, Ffmt, Ftgt, Foptcompile, - Foptlink, FMnf.first, FMnf.second, Fbin.first, Fbin.second, - ImageEntriesPtrs.first, ImageEntriesPtrs.second, - PropSets.get().first, PropSets.get().second)); + ImagesInits.push_back( +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + PreviewBreakingChanges + ? +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + ConstantStruct::get(getSyclDeviceImageTy(), Fver, Fknd, Ffmt, + Ftgt, Foptcompile, Foptlink, Fbin.first, + Fbin.second, ImageEntriesPtrs.first, + ImageEntriesPtrs.second, + PropSets.get().first, PropSets.get().second) +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + : ConstantStruct::get( + getSyclDeviceImageTy(), Fver, Fknd, Ffmt, Ftgt, + Foptcompile, Foptlink, FMnf.first, FMnf.second, + Fbin.first, Fbin.second, ImageEntriesPtrs.first, + ImageEntriesPtrs.second, PropSets.get().first, + PropSets.get().second) +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + ); } else ImagesInits.push_back(ConstantStruct::get( getDeviceImageTy(), Fbin.first, Fbin.second, EntriesB, EntriesE)); @@ -1633,7 +1725,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, const BinaryWrapper::Image &Img) { Out << "\n{\n"; Out << " file = " << Img.File << "\n"; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES Out << " manifest = " << (Img.Manif.empty() ? "-" : Img.Manif) << "\n"; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES Out << " format = " << formatToString(Img.Fmt) << "\n"; Out << " target = " << (Img.Tgt.empty() ? "-" : Img.Tgt) << "\n"; Out << " compile options = " @@ -1789,14 +1883,22 @@ int main(int argc, const char **argv) { cl::ParseCommandLineOptions( argc, argv, "A tool to create a wrapper bitcode for offload target binaries.\n" +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES "Takes offload target binaries and optional manifest files as input\n" +#else + "Takes offload target binaries as input\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES "and produces bitcode file containing target binaries packaged as data\n" "and initialization code which registers target binaries in the offload\n" +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES "runtime. Manifest files format and contents are not restricted and are\n" "a subject of agreement between the device compiler and the native\n" "runtime for that device. When present, manifest file name should\n" "immediately follow the corresponding device image filename on the\n" "command line. Options annotating a device binary have effect on all\n" +#else + "runtime. Options annotating a device binary have effect on all\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES "subsequent input, until redefined.\n" "\n" "For example:\n" @@ -1810,7 +1912,9 @@ int main(int argc, const char **argv) { " -entries=sym.txt \\\n" " -properties=props.txt \\\n" " a.spv \\\n" +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES " a_mf.txt \\\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES " -target=xxx \\\n" " -format=native \\\n" " -compile-opts=\"\" \\\n" @@ -1818,19 +1922,30 @@ int main(int argc, const char **argv) { " -entries=\"\" \\\n" " -properties=\"\" \\\n" " b.bin \\\n" +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES " b_mf.txt \\\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES " -kind=openmp \\\n" " c.bin\\n" "\n" "This command generates an x86 wrapper object (.bc) enclosing the\n" "following tuples describing a single device binary each:\n" "\n" +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES "|offload|target|data |data |manifest|compile|entries|properties|...|\n" "| kind | |format| | |options| | |...|\n" "|-------|------|------|-----|--------|-------|-------|----------|---|\n" "|sycl |spir64|spirv |a.spv|a_mf.txt| -g |sym.txt|props.txt |...|\n" "|sycl |xxx |native|b.bin|b_mf.txt| | | |...|\n" "|openmp |xxx |native|c.bin| | | | |...|\n" +#else + "|offload|target|data |data |compile|entries|properties|...|\n" + "| kind | |format| |options| | |...|\n" + "|-------|------|------|-----|-------|-------|----------|---|\n" + "|sycl |spir64|spirv |a.spv| -g |sym.txt|props.txt |...|\n" + "|sycl |xxx |native|b.bin| | | |...|\n" + "|openmp |xxx |native|c.bin| | | |...|\n" +#endif // __INTEL_PREVIEW_BREAKING_CHANGES "\n" "|...| link |\n" "|...| options |\n" @@ -1897,13 +2012,25 @@ int main(int argc, const char **argv) { // ID != 0 signal that a new image(s) must be added if (ID != 0) { // create an image instance using current state - if (CurInputGroup.size() > 2) { +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + if (!PreviewBreakingChanges && CurInputGroup.size() > 2) { reportError( createStringError(errc::invalid_argument, "too many inputs for a single binary image, " " {opt}expected")); return 1; } +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + if ( +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + PreviewBreakingChanges && +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + CurInputGroup.size() > 1) { + reportError(createStringError(errc::invalid_argument, + "too many inputs for a single binary " + "image, expected")); + return 1; + } if (CurInputGroup.size() != 0) { if (BatchMode) { // transform the batch job (a table of filenames) into a series of @@ -1920,10 +2047,17 @@ int main(int argc, const char **argv) { // iterate via records for (const auto &Row : T.rows()) { - Wr.addImage(Knd, Row.getCell(COL_CODE), - Row.getCell(COL_MANIFEST, ""), Tgt, Fmt, CompileOpts, - LinkOpts, Row.getCell(COL_SYM, ""), - Row.getCell(COL_PROPS, "")); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + if (!PreviewBreakingChanges) + Wr.addImage(Knd, Row.getCell(COL_CODE), + Row.getCell(COL_MANIFEST, ""), Tgt, Fmt, CompileOpts, + LinkOpts, Row.getCell(COL_SYM, ""), + Row.getCell(COL_PROPS, "")); + else +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + Wr.addImage(Knd, Row.getCell(COL_CODE), Tgt, Fmt, CompileOpts, + LinkOpts, Row.getCell(COL_SYM, ""), + Row.getCell(COL_PROPS, "")); } } else { if (Knd == OffloadKind::Unknown) { @@ -1932,9 +2066,15 @@ int main(int argc, const char **argv) { return 1; } StringRef File = CurInputGroup[0]; - StringRef Manif = CurInputGroup.size() > 1 ? CurInputGroup[1] : ""; - Wr.addImage(Knd, File, Manif, Tgt, Fmt, CompileOpts, LinkOpts, - EntriesFile, PropsFile); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + if (!PreviewBreakingChanges) { + StringRef Manif = CurInputGroup.size() > 1 ? CurInputGroup[1] : ""; + Wr.addImage(Knd, File, Manif, Tgt, Fmt, CompileOpts, LinkOpts, + EntriesFile, PropsFile); + } else +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + Wr.addImage(Knd, File, Tgt, Fmt, CompileOpts, LinkOpts, EntriesFile, + PropsFile); } CurInputGroup.clear(); } diff --git a/clang/tools/clang-offload-wrapper/SymPropReader.cpp b/clang/tools/clang-offload-wrapper/SymPropReader.cpp index 448e6f496aa7e..bdc3cf5557cc6 100644 --- a/clang/tools/clang-offload-wrapper/SymPropReader.cpp +++ b/clang/tools/clang-offload-wrapper/SymPropReader.cpp @@ -1,3 +1,20 @@ +//===-- clang-offload-wrapper/SymPropReader.cpp -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Helper class for reading symbol and property information from SYCL +/// device image bitcode files in the context of the clang-offload-wrapper tool. +/// It provides utilities to extract device image initializers, entry names, +/// and property sets from LLVM IR modules, enabling the wrapper to interpret +/// and manage offload image metadata, such as kernel entry points and +/// device-specific properties, for SYCL offloading. +//===----------------------------------------------------------------------===// + #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" @@ -57,10 +74,12 @@ auto getInitializerNumElements(const Constant *Initializer) { // /// a null-terminated string; target- and compiler-specific options // /// which are suggested to use to "link" program at runtime // const char *LinkOptions; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES // /// Pointer to the manifest data start // const unsigned char *ManifestStart; // /// Pointer to the manifest data end // const unsigned char *ManifestEnd; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // /// Pointer to the device binary image start // void *ImageStart; // /// Pointer to the device binary image end diff --git a/llvm/include/llvm/Frontend/Offloading/SYCLOffloadWrapper.h b/llvm/include/llvm/Frontend/Offloading/SYCLOffloadWrapper.h index 5308a4c08b911..ad7f2572a4eef 100644 --- a/llvm/include/llvm/Frontend/Offloading/SYCLOffloadWrapper.h +++ b/llvm/include/llvm/Frontend/Offloading/SYCLOffloadWrapper.h @@ -70,9 +70,13 @@ struct SYCLWrappingOptions { /// Wraps the input bundled images and accompanied data into the module \p M /// as global symbols and registers the images with the SYCL Runtime. /// \param Options Settings that allows to turn on optional data and settings. +/// \param _PreviewBreakingChanges Enable preview breaking changes that are not +/// backward compatible with the existing SYCL Runtime. +/// \returns Error if wrapping fails, success otherwise. llvm::Error wrapSYCLBinaries(llvm::Module &M, const llvm::SmallVector &Images, - SYCLWrappingOptions Options = SYCLWrappingOptions()); + SYCLWrappingOptions Options = SYCLWrappingOptions(), + bool _PreviewBreakingChanges = false); } // namespace offloading } // namespace llvm diff --git a/llvm/lib/Frontend/Offloading/SYCLOffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/SYCLOffloadWrapper.cpp index 075647e3236ab..be88c13e7b226 100644 --- a/llvm/lib/Frontend/Offloading/SYCLOffloadWrapper.cpp +++ b/llvm/lib/Frontend/Offloading/SYCLOffloadWrapper.cpp @@ -46,6 +46,9 @@ using namespace llvm::util; namespace { +/// Enable preview breaking changes. +static bool PreviewBreakingChanges = false; + /// Note: Returned values are a part of ABI. If you want to change them /// then coordinate it with SYCL Runtime. int8_t binaryImageFormatToInt8(SYCLBinaryImageFormat Format) { @@ -137,7 +140,6 @@ struct Wrapper { } // TODO: Drop Version in favor of the Version in Binary Descriptor. - // TODO: Drop Manifest fields. /// Creates a structure corresponding to: /// SYCL specific image descriptor type. /// \code @@ -159,10 +161,12 @@ struct Wrapper { /// // a null-terminated string; target- and compiler-specific options /// // which are suggested to use to "link" program at runtime /// const char *LinkOptions; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES /// // Pointer to the manifest data start /// const unsigned char *ManifestStart; /// // Pointer to the manifest data end /// const unsigned char *ManifestEnd; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES /// // Pointer to the device binary image start /// void *ImageStart; /// // Pointer to the device binary image end @@ -175,24 +179,47 @@ struct Wrapper { /// }; /// \endcode StructType *getSyclDeviceImageTy() { - return StructType::create( - { - Type::getInt16Ty(C), // Version - Type::getInt8Ty(C), // OffloadKind - Type::getInt8Ty(C), // Format - PointerType::getUnqual(C), // DeviceTargetSpec - PointerType::getUnqual(C), // CompileOptions - PointerType::getUnqual(C), // LinkOptions - PointerType::getUnqual(C), // ManifestStart - PointerType::getUnqual(C), // ManifestEnd - PointerType::getUnqual(C), // ImageStart - PointerType::getUnqual(C), // ImageEnd - PointerType::getUnqual(C), // EntriesBegin - PointerType::getUnqual(C), // EntriesEnd - PointerType::getUnqual(C), // PropertySetBegin - PointerType::getUnqual(C) // PropertySetEnd - }, - "__sycl.tgt_device_image"); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + if (!PreviewBreakingChanges) { + return StructType::create( + { + Type::getInt16Ty(C), // Version + Type::getInt8Ty(C), // OffloadKind + Type::getInt8Ty(C), // Format + PointerType::getUnqual(C), // DeviceTargetSpec + PointerType::getUnqual(C), // CompileOptions + PointerType::getUnqual(C), // LinkOptions + PointerType::getUnqual(C), // ManifestStart + PointerType::getUnqual(C), // ManifestEnd + PointerType::getUnqual(C), // ImageStart + PointerType::getUnqual(C), // ImageEnd + PointerType::getUnqual(C), // EntriesBegin + PointerType::getUnqual(C), // EntriesEnd + PointerType::getUnqual(C), // PropertySetBegin + PointerType::getUnqual(C) // PropertySetEnd + }, + "__sycl.tgt_device_image"); + } else { +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + return StructType::create( + { + Type::getInt16Ty(C), // Version + Type::getInt8Ty(C), // OffloadKind + Type::getInt8Ty(C), // Format + PointerType::getUnqual(C), // DeviceTargetSpec + PointerType::getUnqual(C), // CompileOptions + PointerType::getUnqual(C), // LinkOptions + PointerType::getUnqual(C), // ImageStart + PointerType::getUnqual(C), // ImageEnd + PointerType::getUnqual(C), // EntriesBegin + PointerType::getUnqual(C), // EntriesEnd + PointerType::getUnqual(C), // PropertySetBegin + PointerType::getUnqual(C) // PropertySetEnd + }, + "__sycl.tgt_device_image"); +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + } +#endif // __INTEL_PREVIEW_BREAKING_CHANGES } /// Creates a structure for SYCL specific binary descriptor type. Corresponds @@ -545,7 +572,12 @@ struct Wrapper { auto *NullPtr = Constant::getNullValue(PointerType::getUnqual(C)); // DeviceImageStructVersion change log: // -- version 2: updated to PI 1.2 binary image format - constexpr uint16_t DeviceImageStructVersion = 2; + // -- version 3: removed ManifestStart, ManifestEnd pointers +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + uint16_t DeviceImageStructVersion = PreviewBreakingChanges ? 3 : 2; +#else // __INTEL_PREVIEW_BREAKING_CHANGES + constexpr uint16_t DeviceImageStructVersion = 3; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES constexpr uint8_t SYCLOffloadKind = 4; // Corresponds to SYCL auto *Version = ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion); @@ -573,20 +605,33 @@ struct Wrapper { Twine(OffloadKindTag) + ImageID + ".data", Image.Target); } - // TODO: Manifests are going to be removed. - // Note: Manifests are deprecated but corresponding nullptr fields should - // remain to comply ABI. +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES std::pair Manifests = {NullPtr, NullPtr}; +#endif // For SYCL image offload entries are defined here, by wrapper, so // those are created per image std::pair ImageEntriesPtrs = addOffloadEntriesToModule(Image.Entries); - Constant *WrappedImage = ConstantStruct::get( - SyclDeviceImageTy, Version, Kind, Format, Target, CompileOptions, - LinkOptions, Manifests.first, Manifests.second, Binary.first, - Binary.second, ImageEntriesPtrs.first, ImageEntriesPtrs.second, - PropSets.first, PropSets.second); + Constant *WrappedImage = +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + PreviewBreakingChanges + ? +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + ConstantStruct::get(SyclDeviceImageTy, Version, Kind, Format, + Target, CompileOptions, LinkOptions, + Binary.first, Binary.second, + ImageEntriesPtrs.first, ImageEntriesPtrs.second, + PropSets.first, PropSets.second) +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + : ConstantStruct::get( + SyclDeviceImageTy, Version, Kind, Format, Target, + CompileOptions, LinkOptions, Manifests.first, + Manifests.second, Binary.first, Binary.second, + ImageEntriesPtrs.first, ImageEntriesPtrs.second, + PropSets.first, PropSets.second) +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + ; if (Options.EmitRegistrationFunctions) emitRegistrationFunctions(Binary.first, Image.Image->getBufferSize(), @@ -648,20 +693,26 @@ struct Wrapper { /// ... /// static const char ImageN[] = { }; /// - /// static constexpr uint16_t Version = 2; - /// static constexpr uint16_t OffloadKind = 4; // SYCL - /// - /// static const __sycl.tgt_device_image Images[] = { - /// { - /// Version, /*Version*/ - /// OffloadKind, // Kind of offload model. - /// Format, // format of the image - SPIRV, LLVMIR - /// // bc, etc - // NULL, /*DeviceTargetSpec*/ - /// CompileOptions0, /*CompileOptions0*/ - /// LinkOptions0, /*LinkOptions0*/ - /// NULL, /*ManifestStart*/ - /// NULL, /*ManifestEnd*/ +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES +/// static constexpr uint16_t Version = 2; +#else // __INTEL_PREVIEW_BREAKING_CHANGES +/// static constexpr uint16_t Version = 3; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES +/// static constexpr uint16_t OffloadKind = 4; // SYCL +/// +/// static const __sycl.tgt_device_image Images[] = { +/// { +/// Version, /*Version*/ +/// OffloadKind, // Kind of offload model. +/// Format, // format of the image - SPIRV, LLVMIR +/// // bc, etc +// NULL, /*DeviceTargetSpec*/ +/// CompileOptions0, /*CompileOptions0*/ +/// LinkOptions0, /*LinkOptions0*/ +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES +/// NULL, /*ManifestStart*/ +/// NULL, /*ManifestEnd*/ +#endif // __INTEL_PREVIEW_BREAKING_CHANGES /// Image0, /*ImageStart*/ /// Image0 + sizeof(Image0), /*ImageEnd*/ /// __start_offloading_entries0, /*EntriesBegin*/ @@ -785,7 +836,9 @@ struct Wrapper { Error llvm::offloading::wrapSYCLBinaries(llvm::Module &M, const SmallVector &Images, - SYCLWrappingOptions Options) { + SYCLWrappingOptions Options, + bool _PreviewBreakingChanges) { + PreviewBreakingChanges = _PreviewBreakingChanges; Wrapper W(M, Options); GlobalVariable *Desc = W.createFatbinDesc(Images); if (!Desc) diff --git a/sycl/source/detail/compiler.hpp b/sycl/source/detail/compiler.hpp index 90841680ac000..2fc0b56135b20 100644 --- a/sycl/source/detail/compiler.hpp +++ b/sycl/source/detail/compiler.hpp @@ -190,7 +190,11 @@ enum sycl_device_binary_type : uint8_t { }; // Device binary descriptor version supported by this library. +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES static const uint16_t SYCL_DEVICE_BINARY_VERSION = 1; +#else // __INTEL_PREVIEW_BREAKING_CHANGES +static const uint16_t SYCL_DEVICE_BINARY_VERSION = 3; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // The kind of offload model the binary employs; must be 4 for SYCL static const uint8_t SYCL_DEVICE_BINARY_OFFLOAD_KIND_SYCL = 4; @@ -227,10 +231,12 @@ struct sycl_device_binary_struct { /// a null-terminated string; target- and compiler-specific options /// which are suggested to use to "link" program at runtime const char *LinkOptions; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES /// Pointer to the manifest data start const char *ManifestStart; /// Pointer to the manifest data end const char *ManifestEnd; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES /// Pointer to the target code start const unsigned char *BinaryStart; /// Pointer to the target code end diff --git a/sycl/source/detail/device_binary_image.cpp b/sycl/source/detail/device_binary_image.cpp index f339b7280fbce..c8ff57631bb60 100644 --- a/sycl/source/detail/device_binary_image.cpp +++ b/sycl/source/detail/device_binary_image.cpp @@ -219,8 +219,10 @@ DynRTDeviceBinaryImage::DynRTDeviceBinaryImage() Bin->Kind = SYCL_DEVICE_BINARY_OFFLOAD_KIND_SYCL; Bin->CompileOptions = ""; Bin->LinkOptions = ""; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES Bin->ManifestStart = nullptr; Bin->ManifestEnd = nullptr; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES Bin->BinaryStart = nullptr; Bin->BinaryEnd = nullptr; Bin->EntriesBegin = nullptr; diff --git a/sycl/source/detail/jit_device_binaries.cpp b/sycl/source/detail/jit_device_binaries.cpp index c9afd44ab1e52..1be235044dd5d 100644 --- a/sycl/source/detail/jit_device_binaries.cpp +++ b/sycl/source/detail/jit_device_binaries.cpp @@ -110,8 +110,10 @@ sycl_device_binary_struct DeviceBinaryContainer::getPIDeviceBinary( DeviceBinary.Format = Format; DeviceBinary.CompileOptions = CompileOptions ? CompileOptions.get() : ""; DeviceBinary.LinkOptions = ""; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES DeviceBinary.ManifestStart = nullptr; DeviceBinary.ManifestEnd = nullptr; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES // It is safe to use these pointers here, as their lifetime is managed by // the JITContext. DeviceBinary.BinaryStart = BinaryStart; diff --git a/sycl/source/detail/syclbin.cpp b/sycl/source/detail/syclbin.cpp index 229c3eb375571..d1be8d4df6848 100644 --- a/sycl/source/detail/syclbin.cpp +++ b/sycl/source/detail/syclbin.cpp @@ -295,8 +295,10 @@ SYCLBINBinaries::SYCLBINBinaries(const char *SYCLBINContent, size_t SYCLBINSize) __SYCL_DEVICE_BINARY_TARGET_SPIRV64; // TODO: Determine. DeviceBinary.CompileOptions = nullptr; DeviceBinary.LinkOptions = nullptr; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES DeviceBinary.ManifestStart = nullptr; DeviceBinary.ManifestEnd = nullptr; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES DeviceBinary.BinaryStart = reinterpret_cast(IRM.RawIRBytes.data()); DeviceBinary.BinaryEnd = reinterpret_cast( @@ -329,8 +331,10 @@ SYCLBINBinaries::SYCLBINBinaries(const char *SYCLBINContent, size_t SYCLBINSize) getDeviceTargetSpecFromTriple(TargetTriple); DeviceBinary.CompileOptions = nullptr; DeviceBinary.LinkOptions = nullptr; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES DeviceBinary.ManifestStart = nullptr; DeviceBinary.ManifestEnd = nullptr; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES DeviceBinary.BinaryStart = reinterpret_cast( NDCI.RawDeviceCodeImageBytes.data()); DeviceBinary.BinaryEnd = reinterpret_cast( diff --git a/sycl/unittests/compression/CMakeLists.txt b/sycl/unittests/compression/CMakeLists.txt index 065b29d249632..eb1edae8c51a3 100644 --- a/sycl/unittests/compression/CMakeLists.txt +++ b/sycl/unittests/compression/CMakeLists.txt @@ -2,4 +2,4 @@ add_sycl_unittest(CompressionTests OBJECT CompressionTests.cpp ) target_compile_definitions(CompressionTests_non_preview PRIVATE SYCL_RT_ZSTD_AVAILABLE) -target_compile_definitions(CompressionTests_preview PRIVATE SYCL_RT_ZSTD_AVAILABLE) +target_compile_definitions(CompressionTests_preview PRIVATE SYCL_RT_ZSTD_AVAILABLE __INTEL_PREVIEW_BREAKING_CHANGES) diff --git a/sycl/unittests/compression/CompressionTests.cpp b/sycl/unittests/compression/CompressionTests.cpp index 9ce8dda9bc830..d085d8caf8a18 100644 --- a/sycl/unittests/compression/CompressionTests.cpp +++ b/sycl/unittests/compression/CompressionTests.cpp @@ -135,21 +135,28 @@ TEST(CompressionTest, ConcurrentDecompressionOfDeviceImage) { _sycl_offload_entry_struct EntryStruct = { /*addr*/ nullptr, const_cast(EntryName), strlen(EntryName), /*flags*/ 0, /*reserved*/ 0}; - sycl_device_binary_struct BinStruct{/*Version*/ 1, - /*Kind*/ 4, - /*Format*/ SYCL_DEVICE_BINARY_TYPE_SPIRV, - /*DeviceTargetSpec*/ nullptr, - /*CompileOptions*/ nullptr, - /*LinkOptions*/ nullptr, - /*ManifestStart*/ nullptr, - /*ManifestEnd*/ nullptr, - /*BinaryStart*/ compressedDataPtr, - /*BinaryEnd*/ compressedDataPtr + - compressedSize, - /*EntriesBegin*/ &EntryStruct, - /*EntriesEnd*/ &EntryStruct + 1, - /*PropertySetsBegin*/ nullptr, - /*PropertySetsEnd*/ nullptr}; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + sycl_device_binary_struct BinStruct { /*Version*/ + 1, +#else + sycl_device_binary_struct BinStruct{/*Version*/ 3, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*Kind*/ 4, + /*Format*/ SYCL_DEVICE_BINARY_TYPE_SPIRV, + /*DeviceTargetSpec*/ nullptr, + /*CompileOptions*/ nullptr, + /*LinkOptions*/ nullptr, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + /*ManifestStart*/ nullptr, + /*ManifestEnd*/ nullptr, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*BinaryStart*/ compressedDataPtr, + /*BinaryEnd*/ compressedDataPtr + compressedSize, + /*EntriesBegin*/ &EntryStruct, + /*EntriesEnd*/ &EntryStruct + 1, + /*PropertySetsBegin*/ nullptr, + /*PropertySetsEnd*/ nullptr + }; sycl_device_binary Bin = &BinStruct; CompressedRTDeviceBinaryImage Img{Bin}; diff --git a/sycl/unittests/helpers/MockDeviceImage.hpp b/sycl/unittests/helpers/MockDeviceImage.hpp index c38198f5aed64..343e8045b8ac5 100644 --- a/sycl/unittests/helpers/MockDeviceImage.hpp +++ b/sycl/unittests/helpers/MockDeviceImage.hpp @@ -251,13 +251,19 @@ class MockDeviceImage { MockDeviceImage(uint16_t Version, uint8_t Kind, uint8_t Format, const std::string &DeviceTargetSpec, const std::string &CompileOptions, - const std::string &LinkOptions, std::vector &&Manifest, + const std::string &LinkOptions, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + std::vector &&Manifest, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES std::vector &&Binary, internal::LifetimeExtender OffloadEntries, MockPropertySet PropertySet) : MVersion(Version), MKind(Kind), MFormat(Format), MDeviceTargetSpec(DeviceTargetSpec), MCompileOptions(CompileOptions), - MLinkOptions(LinkOptions), MManifest(std::move(Manifest)), + MLinkOptions(LinkOptions), +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + MManifest(std::move(Manifest)), +#endif // __INTEL_PREVIEW_BREAKING_CHANGES MBinary(std::move(Binary)), MOffloadEntries(std::move(OffloadEntries)), MPropertySet(std::move(PropertySet)) { MNativeHandle = { @@ -267,8 +273,10 @@ class MockDeviceImage { MDeviceTargetSpec.c_str(), MCompileOptions.c_str(), MLinkOptions.c_str(), +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES MManifest.empty() ? nullptr : &*MManifest.cbegin(), MManifest.empty() ? nullptr : &*MManifest.crbegin() + 1, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES &*MBinary.begin(), (&*MBinary.begin()) + MBinary.size(), MOffloadEntries.begin(), @@ -283,14 +291,22 @@ class MockDeviceImage { MockDeviceImage(uint16_t Version, uint8_t Kind, uint8_t Format, const std::string &DeviceTargetSpec, const std::string &CompileOptions, - const std::string &LinkOptions, std::vector &&Manifest, + const std::string &LinkOptions, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + std::vector &&Manifest, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES std::vector &&Binary, std::vector &&OffloadEntries, MockPropertySet PropertySet) : MockDeviceImage(Version, Kind, Format, DeviceTargetSpec, CompileOptions, - LinkOptions, std::move(Manifest), std::move(Binary), + LinkOptions, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + std::move(Manifest), +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + std::move(Binary), internal::LifetimeExtender(std::move(OffloadEntries)), - std::move(PropertySet)) {} + std::move(PropertySet)) { + } MockDeviceImage(uint8_t Format, const std::string &DeviceTargetSpec, const std::string &CompileOptions, @@ -300,10 +316,14 @@ class MockDeviceImage { MockPropertySet PropertySet) : MockDeviceImage(SYCL_DEVICE_BINARY_VERSION, SYCL_DEVICE_BINARY_OFFLOAD_KIND_SYCL, Format, - DeviceTargetSpec, CompileOptions, LinkOptions, {}, + DeviceTargetSpec, CompileOptions, LinkOptions, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + {}, // Manifest. +#endif // __INTEL_PREVIEW_BREAKING_CHANGES std::move(Binary), internal::LifetimeExtender(std::move(OffloadEntries)), - std::move(PropertySet)) {} + std::move(PropertySet)) { + } /// Constructs a mock SYCL device image with: /// - the latest version @@ -312,12 +332,17 @@ class MockDeviceImage { /// - placeholder binary data MockDeviceImage(std::vector &&OffloadEntries, MockPropertySet PropertySet) - : MockDeviceImage( - SYCL_DEVICE_BINARY_VERSION, SYCL_DEVICE_BINARY_OFFLOAD_KIND_SYCL, - SYCL_DEVICE_BINARY_TYPE_SPIRV, __SYCL_DEVICE_BINARY_TARGET_SPIRV64, - "", "", {}, std::vector{1, 2, 3, 4, 5}, - internal::LifetimeExtender(std::move(OffloadEntries)), - std::move(PropertySet)) {} + : MockDeviceImage(SYCL_DEVICE_BINARY_VERSION, + SYCL_DEVICE_BINARY_OFFLOAD_KIND_SYCL, + SYCL_DEVICE_BINARY_TYPE_SPIRV, + __SYCL_DEVICE_BINARY_TARGET_SPIRV64, "", "", +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + {}, // Manifest. +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + std::vector{1, 2, 3, 4, 5}, + internal::LifetimeExtender(std::move(OffloadEntries)), + std::move(PropertySet)) { + } /// Constructs a mock SYCL device image with: /// - the latest version @@ -338,7 +363,9 @@ class MockDeviceImage { std::string MDeviceTargetSpec; std::string MCompileOptions; std::string MLinkOptions; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES std::vector MManifest; +#endif // __INTEL_PREVIEW_BREAKING_CHANGES std::vector MBinary; internal::LifetimeExtender MOffloadEntries; MockPropertySet MPropertySet; diff --git a/sycl/unittests/kernel-and-program/CMakeLists.txt b/sycl/unittests/kernel-and-program/CMakeLists.txt index d912cfbaa9d09..2ac6af2296f83 100644 --- a/sycl/unittests/kernel-and-program/CMakeLists.txt +++ b/sycl/unittests/kernel-and-program/CMakeLists.txt @@ -9,5 +9,5 @@ add_sycl_unittest(KernelAndProgramTests OBJECT OutOfResources.cpp InMemCacheEviction.cpp ) -target_compile_definitions(KernelAndProgramTests_non_preview PRIVATE -D__SYCL_INTERNAL_API) -target_compile_definitions(KernelAndProgramTests_preview PRIVATE -D__SYCL_INTERNAL_API) +target_compile_definitions(KernelAndProgramTests_non_preview PRIVATE __SYCL_INTERNAL_API) +target_compile_definitions(KernelAndProgramTests_preview PRIVATE __SYCL_INTERNAL_API __INTEL_PREVIEW_BREAKING_CHANGES) diff --git a/sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp b/sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp index 1ef47e28c0872..32e914086472a 100644 --- a/sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp +++ b/sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp @@ -263,20 +263,28 @@ class PersistentDeviceCodeCache _sycl_offload_entry_struct EntryStruct = { /*addr*/ nullptr, const_cast(EntryName), strlen(EntryName), /*flags*/ 0, /*reserved*/ 0}; - sycl_device_binary_struct BinStruct{/*Version*/ 1, - /*Kind*/ 4, - /*Format*/ GetParam(), - /*DeviceTargetSpec*/ nullptr, - /*CompileOptions*/ nullptr, - /*LinkOptions*/ nullptr, - /*ManifestStart*/ nullptr, - /*ManifestEnd*/ nullptr, - /*BinaryStart*/ nullptr, - /*BinaryEnd*/ nullptr, - /*EntriesBegin*/ &EntryStruct, - /*EntriesEnd*/ &EntryStruct + 1, - /*PropertySetsBegin*/ nullptr, - /*PropertySetsEnd*/ nullptr}; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + sycl_device_binary_struct BinStruct { /*Version*/ + 1, +#else + sycl_device_binary_struct BinStruct{/*Version*/ 3, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*Kind*/ 4, + /*Format*/ GetParam(), + /*DeviceTargetSpec*/ nullptr, + /*CompileOptions*/ nullptr, + /*LinkOptions*/ nullptr, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + /*ManifestStart*/ nullptr, + /*ManifestEnd*/ nullptr, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*BinaryStart*/ nullptr, + /*BinaryEnd*/ nullptr, + /*EntriesBegin*/ &EntryStruct, + /*EntriesEnd*/ &EntryStruct + 1, + /*PropertySetsBegin*/ nullptr, + /*PropertySetsEnd*/ nullptr + }; sycl_device_binary Bin = &BinStruct; detail::RTDeviceBinaryImage Img{Bin}; ur_program_handle_t NativeProg; @@ -313,20 +321,28 @@ TEST_P(PersistentDeviceCodeCache, MultipleImages) { _sycl_offload_entry_struct ExtraEntryStruct = { /*addr*/ nullptr, const_cast(ExtraEntryName), strlen(ExtraEntryName), /*flags*/ 0, /*reserved*/ 0}; - sycl_device_binary_struct ExtraBinStruct{/*Version*/ 1, - /*Kind*/ 4, - /*Format*/ GetParam(), - /*DeviceTargetSpec*/ nullptr, - /*CompileOptions*/ nullptr, - /*LinkOptions*/ nullptr, - /*ManifestStart*/ nullptr, - /*ManifestEnd*/ nullptr, - /*BinaryStart*/ nullptr, - /*BinaryEnd*/ nullptr, - /*EntriesBegin*/ &ExtraEntryStruct, - /*EntriesEnd*/ &ExtraEntryStruct + 1, - /*PropertySetsBegin*/ nullptr, - /*PropertySetsEnd*/ nullptr}; +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + sycl_device_binary_struct ExtraBinStruct { /*Version*/ + 1, +#else + sycl_device_binary_struct ExtraBinStruct{/*Version*/ 3, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*Kind*/ 4, + /*Format*/ GetParam(), + /*DeviceTargetSpec*/ nullptr, + /*CompileOptions*/ nullptr, + /*LinkOptions*/ nullptr, +#ifndef __INTEL_PREVIEW_BREAKING_CHANGES + /*ManifestStart*/ nullptr, + /*ManifestEnd*/ nullptr, +#endif // __INTEL_PREVIEW_BREAKING_CHANGES + /*BinaryStart*/ nullptr, + /*BinaryEnd*/ nullptr, + /*EntriesBegin*/ &ExtraEntryStruct, + /*EntriesEnd*/ &ExtraEntryStruct + 1, + /*PropertySetsBegin*/ nullptr, + /*PropertySetsEnd*/ nullptr + }; sycl_device_binary ExtraBin = &ExtraBinStruct; detail::RTDeviceBinaryImage ExtraImg{ExtraBin}; std::string BuildOptions{"--multiple-images"};