[Offload][NFC] Offload wrapper cleanup/refactoring (#169411)
Addresses feedback from https://github.com/llvm/llvm-project/pull/147508#pullrequestreview-3272708203 : - Update access modifiers for SYCLWrapper members. - Update comments. - Update types.
This commit is contained in:
parent
ab5ae9a61f
commit
4e7ce57e0e
@ -56,18 +56,18 @@ LLVM_ABI llvm::Error wrapHIPBinary(llvm::Module &M, llvm::ArrayRef<char> Images,
|
||||
bool EmitSurfacesAndTextures = true);
|
||||
|
||||
struct SYCLJITOptions {
|
||||
// Target/compiler specific options that are suggested to use to "compile"
|
||||
// program at runtime.
|
||||
// Target/compiler specific options that are passed to the device compiler at
|
||||
// runtime.
|
||||
std::string CompileOptions;
|
||||
// Target/compiler specific options that are suggested to use to "link"
|
||||
// program at runtime.
|
||||
// Target/compiler specific options that are passed to the device linker at
|
||||
// runtime.
|
||||
std::string LinkOptions;
|
||||
};
|
||||
|
||||
/// Wraps OffloadBinaries in the given \p Buffers into the module \p M
|
||||
/// as global symbols and registers the images with the SYCL Runtime.
|
||||
/// \param Options Compiler and linker options to be encoded for the later
|
||||
/// use by a runtime for JIT compilation.
|
||||
/// use by a runtime for JIT compilation. Not used for AOT.
|
||||
LLVM_ABI llvm::Error
|
||||
wrapSYCLBinaries(llvm::Module &M, llvm::ArrayRef<char> Buffer,
|
||||
SYCLJITOptions Options = SYCLJITOptions());
|
||||
|
||||
@ -640,15 +640,8 @@ void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc,
|
||||
}
|
||||
|
||||
/// SYCLWrapper helper class that creates all LLVM IRs wrapping given images.
|
||||
struct SYCLWrapper {
|
||||
Module &M;
|
||||
LLVMContext &C;
|
||||
SYCLJITOptions Options;
|
||||
|
||||
StructType *EntryTy = nullptr;
|
||||
StructType *SyclDeviceImageTy = nullptr;
|
||||
StructType *SyclBinDescTy = nullptr;
|
||||
|
||||
class SYCLWrapper {
|
||||
public:
|
||||
SYCLWrapper(Module &M, const SYCLJITOptions &Options)
|
||||
: M(M), C(M.getContext()), Options(Options) {
|
||||
EntryTy = offloading::getEntryTy(M);
|
||||
@ -656,259 +649,6 @@ struct SYCLWrapper {
|
||||
SyclBinDescTy = getSyclBinDescTy();
|
||||
}
|
||||
|
||||
IntegerType *getSizeTTy() {
|
||||
switch (M.getDataLayout().getPointerSize()) {
|
||||
case 4:
|
||||
return Type::getInt32Ty(C);
|
||||
case 8:
|
||||
return Type::getInt64Ty(C);
|
||||
}
|
||||
llvm_unreachable("unsupported pointer type size");
|
||||
}
|
||||
|
||||
SmallVector<Constant *, 2> getSizetConstPair(size_t First, size_t Second) {
|
||||
IntegerType *SizeTTy = getSizeTTy();
|
||||
return SmallVector<Constant *, 2>{ConstantInt::get(SizeTTy, First),
|
||||
ConstantInt::get(SizeTTy, Second)};
|
||||
}
|
||||
|
||||
/// Note: Properties aren't supported and the support is going
|
||||
/// to be added later.
|
||||
/// Creates a structure corresponding to:
|
||||
/// SYCL specific image descriptor type.
|
||||
/// \code
|
||||
/// struct __sycl.tgt_device_image {
|
||||
/// // version of this structure - for backward compatibility;
|
||||
/// // all modifications which change order/type/offsets of existing fields
|
||||
/// // should increment the version.
|
||||
/// uint16_t Version;
|
||||
/// // the kind of offload model the image employs.
|
||||
/// uint8_t OffloadKind;
|
||||
/// // format of the image data - SPIRV, LLVMIR bitcode, etc
|
||||
/// uint8_t Format;
|
||||
/// // null-terminated string representation of the device's target
|
||||
/// // architecture
|
||||
/// const char *Arch;
|
||||
/// // a null-terminated string; target- and compiler-specific options
|
||||
/// // which are suggested to use to "compile" program at runtime
|
||||
/// const char *CompileOptions;
|
||||
/// // 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 device binary image start
|
||||
/// void *ImageStart;
|
||||
/// // Pointer to the device binary image end
|
||||
/// void *ImageEnd;
|
||||
/// // the entry table
|
||||
/// __tgt_offload_entry *EntriesBegin;
|
||||
/// __tgt_offload_entry *EntriesEnd;
|
||||
/// const char *PropertiesBegin;
|
||||
/// const char *PropertiesEnd;
|
||||
/// };
|
||||
/// \endcode
|
||||
StructType *getSyclDeviceImageTy() {
|
||||
return StructType::create(
|
||||
{
|
||||
Type::getInt16Ty(C), // Version
|
||||
Type::getInt8Ty(C), // OffloadKind
|
||||
Type::getInt8Ty(C), // Format
|
||||
PointerType::getUnqual(C), // Arch
|
||||
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), // PropertiesBegin
|
||||
PointerType::getUnqual(C) // PropertiesEnd
|
||||
},
|
||||
"__sycl.tgt_device_image");
|
||||
}
|
||||
|
||||
/// Creates a structure for SYCL specific binary descriptor type. Corresponds
|
||||
/// to:
|
||||
///
|
||||
/// \code
|
||||
/// struct __sycl.tgt_bin_desc {
|
||||
/// // version of this structure - for backward compatibility;
|
||||
/// // all modifications which change order/type/offsets of existing fields
|
||||
/// // should increment the version.
|
||||
/// uint16_t Version;
|
||||
/// uint16_t NumDeviceImages;
|
||||
/// __sycl.tgt_device_image *DeviceImages;
|
||||
/// // the offload entry table
|
||||
/// __tgt_offload_entry *HostEntriesBegin;
|
||||
/// __tgt_offload_entry *HostEntriesEnd;
|
||||
/// };
|
||||
/// \endcode
|
||||
StructType *getSyclBinDescTy() {
|
||||
return StructType::create(
|
||||
{Type::getInt16Ty(C), Type::getInt16Ty(C), PointerType::getUnqual(C),
|
||||
PointerType::getUnqual(C), PointerType::getUnqual(C)},
|
||||
"__sycl.tgt_bin_desc");
|
||||
}
|
||||
|
||||
/// Adds a global readonly variable that is initialized by given
|
||||
/// \p Initializer to the module.
|
||||
GlobalVariable *addGlobalArrayVariable(const Twine &Name,
|
||||
ArrayRef<char> Initializer,
|
||||
const Twine &Section = "") {
|
||||
auto *Arr = ConstantDataArray::get(M.getContext(), Initializer);
|
||||
auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Arr, Name);
|
||||
Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
SmallVector<char, 32> NameBuf;
|
||||
auto SectionName = Section.toStringRef(NameBuf);
|
||||
if (!SectionName.empty())
|
||||
Var->setSection(SectionName);
|
||||
return Var;
|
||||
}
|
||||
|
||||
/// Adds given \p Buf as a global variable into the module.
|
||||
/// \returns Pair of pointers that point at the beginning and the end of the
|
||||
/// variable.
|
||||
std::pair<Constant *, Constant *>
|
||||
addArrayToModule(ArrayRef<char> Buf, const Twine &Name,
|
||||
const Twine &Section = "") {
|
||||
auto *Var = addGlobalArrayVariable(Name, Buf, Section);
|
||||
auto *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var,
|
||||
getSizetConstPair(0, 0));
|
||||
auto *ImageE = ConstantExpr::getGetElementPtr(
|
||||
Var->getValueType(), Var, getSizetConstPair(0, Buf.size()));
|
||||
return std::make_pair(ImageB, ImageE);
|
||||
}
|
||||
|
||||
/// Adds given \p Data as constant byte array in the module.
|
||||
/// \returns Constant pointer to the added data. The pointer type does not
|
||||
/// carry size information.
|
||||
Constant *addRawDataToModule(ArrayRef<char> Data, const Twine &Name) {
|
||||
auto *Var = addGlobalArrayVariable(Name, Data);
|
||||
auto *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var,
|
||||
getSizetConstPair(0, 0));
|
||||
return DataPtr;
|
||||
}
|
||||
|
||||
/// Creates a global variable of const char* type and creates an
|
||||
/// initializer that initializes it with \p Str.
|
||||
///
|
||||
/// \returns Link-time constant pointer (constant expr) to that
|
||||
/// variable.
|
||||
Constant *addStringToModule(StringRef Str, const Twine &Name) {
|
||||
auto *Arr = ConstantDataArray::getString(C, Str);
|
||||
auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Arr, Name);
|
||||
Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
auto *Zero = ConstantInt::get(getSizeTTy(), 0);
|
||||
Constant *ZeroZero[] = {Zero, Zero};
|
||||
return ConstantExpr::getGetElementPtr(Var->getValueType(), Var, ZeroZero);
|
||||
}
|
||||
|
||||
/// Each image contains its own set of symbols, which may contain different
|
||||
/// symbols than other images. This function constructs an array of
|
||||
/// symbol entries for a particular image.
|
||||
///
|
||||
/// \returns Pointers to the beginning and end of the array.
|
||||
std::pair<Constant *, Constant *>
|
||||
initOffloadEntriesPerImage(StringRef Entries, const Twine &OffloadKindTag) {
|
||||
SmallVector<Constant *> EntriesInits;
|
||||
std::unique_ptr<MemoryBuffer> MB = MemoryBuffer::getMemBuffer(
|
||||
Entries, /*BufferName*/ "", /*RequiresNullTerminator*/ false);
|
||||
for (line_iterator LI(*MB); !LI.is_at_eof(); ++LI) {
|
||||
GlobalVariable *GV =
|
||||
emitOffloadingEntry(M, /*Kind*/ OffloadKind::OFK_SYCL,
|
||||
Constant::getNullValue(PointerType::getUnqual(C)),
|
||||
/*Name*/ *LI, /*Size*/ 0,
|
||||
/*Flags*/ 0, /*Data*/ 0);
|
||||
EntriesInits.push_back(GV->getInitializer());
|
||||
}
|
||||
|
||||
auto *Arr = ConstantArray::get(ArrayType::get(EntryTy, EntriesInits.size()),
|
||||
EntriesInits);
|
||||
auto *EntriesGV = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Arr,
|
||||
OffloadKindTag + "entries_arr");
|
||||
|
||||
auto *EntriesB = ConstantExpr::getGetElementPtr(
|
||||
EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, 0));
|
||||
auto *EntriesE = ConstantExpr::getGetElementPtr(
|
||||
EntriesGV->getValueType(), EntriesGV,
|
||||
getSizetConstPair(0, EntriesInits.size()));
|
||||
return std::make_pair(EntriesB, EntriesE);
|
||||
}
|
||||
|
||||
Constant *wrapImage(const OffloadBinary &OB, const Twine &ImageID,
|
||||
StringRef OffloadKindTag) {
|
||||
// Note: Intel DPC++ compiler had 2 versions of this structure
|
||||
// and clang++ has a third different structure. To avoid ABI incompatibility
|
||||
// between generated device images the Version here starts from 3.
|
||||
constexpr uint16_t DeviceImageStructVersion = 3;
|
||||
Constant *Version =
|
||||
ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion);
|
||||
Constant *OffloadKindConstant = ConstantInt::get(
|
||||
Type::getInt8Ty(C), static_cast<uint8_t>(OB.getOffloadKind()));
|
||||
Constant *ImageKindConstant = ConstantInt::get(
|
||||
Type::getInt8Ty(C), static_cast<uint8_t>(OB.getImageKind()));
|
||||
StringRef Triple = OB.getString("triple");
|
||||
Constant *TripleConstant =
|
||||
addStringToModule(Triple, Twine(OffloadKindTag) + "target." + ImageID);
|
||||
Constant *CompileOptions =
|
||||
addStringToModule(Options.CompileOptions,
|
||||
Twine(OffloadKindTag) + "opts.compile." + ImageID);
|
||||
Constant *LinkOptions = addStringToModule(
|
||||
Options.LinkOptions, Twine(OffloadKindTag) + "opts.link." + ImageID);
|
||||
|
||||
// Note: NULL for now.
|
||||
std::pair<Constant *, Constant *> PropertiesConstants = {
|
||||
Constant::getNullValue(PointerType::getUnqual(C)),
|
||||
Constant::getNullValue(PointerType::getUnqual(C))};
|
||||
|
||||
StringRef RawImage = OB.getImage();
|
||||
std::pair<Constant *, Constant *> Binary = addArrayToModule(
|
||||
ArrayRef<char>(RawImage.begin(), RawImage.end()),
|
||||
Twine(OffloadKindTag) + ImageID + ".data", ".llvm.offloading");
|
||||
|
||||
// For SYCL images offload entries are defined here per image.
|
||||
std::pair<Constant *, Constant *> ImageEntriesPtrs =
|
||||
initOffloadEntriesPerImage(OB.getString("symbols"), OffloadKindTag);
|
||||
Constant *WrappedBinary = ConstantStruct::get(
|
||||
SyclDeviceImageTy, Version, OffloadKindConstant, ImageKindConstant,
|
||||
TripleConstant, CompileOptions, LinkOptions, Binary.first,
|
||||
Binary.second, ImageEntriesPtrs.first, ImageEntriesPtrs.second,
|
||||
PropertiesConstants.first, PropertiesConstants.second);
|
||||
|
||||
return WrappedBinary;
|
||||
}
|
||||
|
||||
GlobalVariable *combineWrappedImages(ArrayRef<Constant *> WrappedImages,
|
||||
StringRef OffloadKindTag) {
|
||||
auto *ImagesData = ConstantArray::get(
|
||||
ArrayType::get(SyclDeviceImageTy, WrappedImages.size()), WrappedImages);
|
||||
auto *ImagesGV =
|
||||
new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, ImagesData,
|
||||
Twine(OffloadKindTag) + "device_images");
|
||||
ImagesGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
auto *Zero = ConstantInt::get(getSizeTTy(), 0);
|
||||
Constant *ZeroZero[] = {Zero, Zero};
|
||||
auto *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(),
|
||||
ImagesGV, ZeroZero);
|
||||
|
||||
Constant *EntriesB = Constant::getNullValue(PointerType::getUnqual(C));
|
||||
Constant *EntriesE = Constant::getNullValue(PointerType::getUnqual(C));
|
||||
static constexpr uint16_t BinDescStructVersion = 1;
|
||||
auto *DescInit = ConstantStruct::get(
|
||||
SyclBinDescTy,
|
||||
ConstantInt::get(Type::getInt16Ty(C), BinDescStructVersion),
|
||||
ConstantInt::get(Type::getInt16Ty(C), WrappedImages.size()), ImagesB,
|
||||
EntriesB, EntriesE);
|
||||
|
||||
return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, DescInit,
|
||||
Twine(OffloadKindTag) + "descriptor");
|
||||
}
|
||||
|
||||
/// Creates binary descriptor for the given device images. Binary descriptor
|
||||
/// is an object that is passed to the offloading runtime at program startup
|
||||
/// and it describes all device images available in the executable or shared
|
||||
@ -972,19 +712,20 @@ struct SYCLWrapper {
|
||||
}
|
||||
|
||||
void createRegisterFatbinFunction(GlobalVariable *FatbinDesc) {
|
||||
auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
Twine("sycl") + ".descriptor_reg", &M);
|
||||
FunctionType *FuncTy =
|
||||
FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
Twine("sycl") + ".descriptor_reg", &M);
|
||||
Func->setSection(".text.startup");
|
||||
|
||||
// Get RegFuncName function declaration.
|
||||
auto *RegFuncTy =
|
||||
FunctionType *RegFuncTy =
|
||||
FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C),
|
||||
/*isVarArg=*/false);
|
||||
FunctionCallee RegFuncC =
|
||||
M.getOrInsertFunction("__sycl_register_lib", RegFuncTy);
|
||||
|
||||
// Construct function body
|
||||
// Construct function body.
|
||||
IRBuilder Builder(BasicBlock::Create(C, "entry", Func));
|
||||
Builder.CreateCall(RegFuncC, FatbinDesc);
|
||||
Builder.CreateRetVoid();
|
||||
@ -994,13 +735,14 @@ struct SYCLWrapper {
|
||||
}
|
||||
|
||||
void createUnregisterFunction(GlobalVariable *FatbinDesc) {
|
||||
auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
"sycl.descriptor_unreg", &M);
|
||||
FunctionType *FuncTy =
|
||||
FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
"sycl.descriptor_unreg", &M);
|
||||
Func->setSection(".text.startup");
|
||||
|
||||
// Get UnregFuncName function declaration.
|
||||
auto *UnRegFuncTy =
|
||||
FunctionType *UnRegFuncTy =
|
||||
FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C),
|
||||
/*isVarArg=*/false);
|
||||
FunctionCallee UnRegFuncC =
|
||||
@ -1014,6 +756,273 @@ struct SYCLWrapper {
|
||||
// Add this function to global destructors.
|
||||
appendToGlobalDtors(M, Func, /*Priority*/ 1);
|
||||
}
|
||||
|
||||
private:
|
||||
IntegerType *getSizeTTy() {
|
||||
switch (M.getDataLayout().getPointerSize()) {
|
||||
case 4:
|
||||
return Type::getInt32Ty(C);
|
||||
case 8:
|
||||
return Type::getInt64Ty(C);
|
||||
}
|
||||
llvm_unreachable("unsupported pointer type size");
|
||||
}
|
||||
|
||||
SmallVector<Constant *, 2> getSizetConstPair(size_t First, size_t Second) {
|
||||
IntegerType *SizeTTy = getSizeTTy();
|
||||
return SmallVector<Constant *, 2>{ConstantInt::get(SizeTTy, First),
|
||||
ConstantInt::get(SizeTTy, Second)};
|
||||
}
|
||||
|
||||
/// Note: Properties aren't supported and the support is going
|
||||
/// to be added later.
|
||||
/// Creates a structure corresponding to:
|
||||
/// SYCL specific image descriptor type.
|
||||
/// \code
|
||||
/// struct __sycl.tgt_device_image {
|
||||
/// // Version of this structure - for backward compatibility;
|
||||
/// // all modifications which change order/type/offsets of existing fields
|
||||
/// // should increment the version.
|
||||
/// uint16_t Version;
|
||||
/// // The kind of offload model the image employs.
|
||||
/// uint8_t OffloadKind;
|
||||
/// // Format of the image data - SPIRV, LLVMIR bitcode, etc.
|
||||
/// uint8_t Format;
|
||||
/// // Null-terminated string representation of the device's target
|
||||
/// // architecture.
|
||||
/// const char *Arch;
|
||||
/// // A null-terminated string; target- and compiler-specific options
|
||||
/// // which are passed to the device compiler at runtime.
|
||||
/// const char *CompileOptions;
|
||||
/// // A null-terminated string; target- and compiler-specific options
|
||||
/// // which are passed to the device linker at runtime.
|
||||
/// const char *LinkOptions;
|
||||
/// // Pointer to the device binary image start.
|
||||
/// void *ImageStart;
|
||||
/// // Pointer to the device binary image end.
|
||||
/// void *ImageEnd;
|
||||
/// // The entry table.
|
||||
/// __tgt_offload_entry *EntriesBegin;
|
||||
/// __tgt_offload_entry *EntriesEnd;
|
||||
/// const char *PropertiesBegin;
|
||||
/// const char *PropertiesEnd;
|
||||
/// };
|
||||
/// \endcode
|
||||
StructType *getSyclDeviceImageTy() {
|
||||
return StructType::create(
|
||||
{
|
||||
Type::getInt16Ty(C), // Version
|
||||
Type::getInt8Ty(C), // OffloadKind
|
||||
Type::getInt8Ty(C), // Format
|
||||
PointerType::getUnqual(C), // Arch
|
||||
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), // PropertiesBegin
|
||||
PointerType::getUnqual(C) // PropertiesEnd
|
||||
},
|
||||
"__sycl.tgt_device_image");
|
||||
}
|
||||
|
||||
/// Creates a structure for SYCL specific binary descriptor type. Corresponds
|
||||
/// to:
|
||||
///
|
||||
/// \code
|
||||
/// struct __sycl.tgt_bin_desc {
|
||||
/// // version of this structure - for backward compatibility;
|
||||
/// // all modifications which change order/type/offsets of existing fields
|
||||
/// // should increment the version.
|
||||
/// uint16_t Version;
|
||||
/// uint16_t NumDeviceImages;
|
||||
/// __sycl.tgt_device_image *DeviceImages;
|
||||
/// // the offload entry table
|
||||
/// __tgt_offload_entry *HostEntriesBegin;
|
||||
/// __tgt_offload_entry *HostEntriesEnd;
|
||||
/// };
|
||||
/// \endcode
|
||||
StructType *getSyclBinDescTy() {
|
||||
return StructType::create(
|
||||
{Type::getInt16Ty(C), Type::getInt16Ty(C), PointerType::getUnqual(C),
|
||||
PointerType::getUnqual(C), PointerType::getUnqual(C)},
|
||||
"__sycl.tgt_bin_desc");
|
||||
}
|
||||
|
||||
/// Adds a global readonly variable that is initialized by given
|
||||
/// \p Initializer to the module.
|
||||
GlobalVariable *addGlobalArrayVariable(const Twine &Name,
|
||||
ArrayRef<char> Initializer,
|
||||
const Twine &Section = "") {
|
||||
Constant *Arr = ConstantDataArray::get(M.getContext(), Initializer);
|
||||
GlobalVariable *Var =
|
||||
new GlobalVariable(M, Arr->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Arr, Name);
|
||||
Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
SmallVector<char, 32> NameBuf;
|
||||
StringRef SectionName = Section.toStringRef(NameBuf);
|
||||
if (!SectionName.empty())
|
||||
Var->setSection(SectionName);
|
||||
return Var;
|
||||
}
|
||||
|
||||
/// Adds given \p Buf as a global variable into the module.
|
||||
/// \returns Pair of pointers that point at the beginning and the end of the
|
||||
/// variable.
|
||||
std::pair<Constant *, Constant *>
|
||||
addArrayToModule(ArrayRef<char> Buf, const Twine &Name,
|
||||
const Twine &Section = "") {
|
||||
GlobalVariable *Var = addGlobalArrayVariable(Name, Buf, Section);
|
||||
Constant *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var,
|
||||
getSizetConstPair(0, 0));
|
||||
Constant *ImageE = ConstantExpr::getGetElementPtr(
|
||||
Var->getValueType(), Var, getSizetConstPair(0, Buf.size()));
|
||||
return std::make_pair(ImageB, ImageE);
|
||||
}
|
||||
|
||||
/// Adds given \p Data as constant byte array in the module.
|
||||
/// \returns Constant pointer to the added data. The pointer type does not
|
||||
/// carry size information.
|
||||
Constant *addRawDataToModule(ArrayRef<char> Data, const Twine &Name) {
|
||||
GlobalVariable *Var = addGlobalArrayVariable(Name, Data);
|
||||
Constant *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var,
|
||||
getSizetConstPair(0, 0));
|
||||
return DataPtr;
|
||||
}
|
||||
|
||||
/// Creates a global variable of const char* type and creates an
|
||||
/// initializer that initializes it with \p Str.
|
||||
///
|
||||
/// \returns Link-time constant pointer (constant expr) to that
|
||||
/// variable.
|
||||
Constant *addStringToModule(StringRef Str, const Twine &Name) {
|
||||
Constant *Arr = ConstantDataArray::getString(C, Str);
|
||||
GlobalVariable *Var =
|
||||
new GlobalVariable(M, Arr->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Arr, Name);
|
||||
Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0);
|
||||
Constant *ZeroZero[] = {Zero, Zero};
|
||||
return ConstantExpr::getGetElementPtr(Var->getValueType(), Var, ZeroZero);
|
||||
}
|
||||
|
||||
/// Each image contains its own set of symbols, which may contain different
|
||||
/// symbols than other images. This function constructs an array of
|
||||
/// symbol entries for a particular image.
|
||||
///
|
||||
/// \returns Pointers to the beginning and end of the array.
|
||||
std::pair<Constant *, Constant *>
|
||||
initOffloadEntriesPerImage(StringRef Entries, const Twine &OffloadKindTag) {
|
||||
SmallVector<Constant *> EntriesInits;
|
||||
std::unique_ptr<MemoryBuffer> MB = MemoryBuffer::getMemBuffer(
|
||||
Entries, /*BufferName*/ "", /*RequiresNullTerminator*/ false);
|
||||
for (line_iterator LI(*MB); !LI.is_at_eof(); ++LI) {
|
||||
GlobalVariable *GV =
|
||||
emitOffloadingEntry(M, /*Kind*/ OffloadKind::OFK_SYCL,
|
||||
Constant::getNullValue(PointerType::getUnqual(C)),
|
||||
/*Name*/ *LI, /*Size*/ 0,
|
||||
/*Flags*/ 0, /*Data*/ 0);
|
||||
EntriesInits.push_back(GV->getInitializer());
|
||||
}
|
||||
|
||||
Constant *Arr = ConstantArray::get(
|
||||
ArrayType::get(EntryTy, EntriesInits.size()), EntriesInits);
|
||||
GlobalVariable *EntriesGV = new GlobalVariable(
|
||||
M, Arr->getType(), /*isConstant*/ true, GlobalVariable::InternalLinkage,
|
||||
Arr, OffloadKindTag + "entries_arr");
|
||||
|
||||
Constant *EntriesB = ConstantExpr::getGetElementPtr(
|
||||
EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, 0));
|
||||
Constant *EntriesE = ConstantExpr::getGetElementPtr(
|
||||
EntriesGV->getValueType(), EntriesGV,
|
||||
getSizetConstPair(0, EntriesInits.size()));
|
||||
return std::make_pair(EntriesB, EntriesE);
|
||||
}
|
||||
|
||||
Constant *wrapImage(const OffloadBinary &OB, const Twine &ImageID,
|
||||
StringRef OffloadKindTag) {
|
||||
// Note: Intel DPC++ compiler had 2 versions of this structure
|
||||
// and clang++ has a third different structure. To avoid ABI incompatibility
|
||||
// between generated device images the Version here starts from 3.
|
||||
constexpr uint16_t DeviceImageStructVersion = 3;
|
||||
Constant *Version =
|
||||
ConstantInt::get(Type::getInt16Ty(C), DeviceImageStructVersion);
|
||||
Constant *OffloadKindConstant = ConstantInt::get(
|
||||
Type::getInt8Ty(C), static_cast<uint8_t>(OB.getOffloadKind()));
|
||||
Constant *ImageKindConstant = ConstantInt::get(
|
||||
Type::getInt8Ty(C), static_cast<uint8_t>(OB.getImageKind()));
|
||||
StringRef Triple = OB.getString("triple");
|
||||
Constant *TripleConstant =
|
||||
addStringToModule(Triple, Twine(OffloadKindTag) + "target." + ImageID);
|
||||
Constant *CompileOptions =
|
||||
addStringToModule(Options.CompileOptions,
|
||||
Twine(OffloadKindTag) + "opts.compile." + ImageID);
|
||||
Constant *LinkOptions = addStringToModule(
|
||||
Options.LinkOptions, Twine(OffloadKindTag) + "opts.link." + ImageID);
|
||||
|
||||
// Note: NULL for now.
|
||||
std::pair<Constant *, Constant *> PropertiesConstants = {
|
||||
Constant::getNullValue(PointerType::getUnqual(C)),
|
||||
Constant::getNullValue(PointerType::getUnqual(C))};
|
||||
|
||||
StringRef RawImage = OB.getImage();
|
||||
std::pair<Constant *, Constant *> Binary = addArrayToModule(
|
||||
ArrayRef<char>(RawImage.begin(), RawImage.end()),
|
||||
Twine(OffloadKindTag) + ImageID + ".data", ".llvm.offloading");
|
||||
|
||||
// For SYCL images offload entries are defined here per image.
|
||||
std::pair<Constant *, Constant *> ImageEntriesPtrs =
|
||||
initOffloadEntriesPerImage(OB.getString("symbols"), OffloadKindTag);
|
||||
|
||||
// .first and .second arguments below correspond to start and end pointers
|
||||
// respectively.
|
||||
Constant *WrappedBinary = ConstantStruct::get(
|
||||
SyclDeviceImageTy, Version, OffloadKindConstant, ImageKindConstant,
|
||||
TripleConstant, CompileOptions, LinkOptions, Binary.first,
|
||||
Binary.second, ImageEntriesPtrs.first, ImageEntriesPtrs.second,
|
||||
PropertiesConstants.first, PropertiesConstants.second);
|
||||
|
||||
return WrappedBinary;
|
||||
}
|
||||
|
||||
GlobalVariable *combineWrappedImages(ArrayRef<Constant *> WrappedImages,
|
||||
StringRef OffloadKindTag) {
|
||||
Constant *ImagesData = ConstantArray::get(
|
||||
ArrayType::get(SyclDeviceImageTy, WrappedImages.size()), WrappedImages);
|
||||
GlobalVariable *ImagesGV =
|
||||
new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, ImagesData,
|
||||
Twine(OffloadKindTag) + "device_images");
|
||||
ImagesGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0);
|
||||
Constant *ZeroZero[] = {Zero, Zero};
|
||||
Constant *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(),
|
||||
ImagesGV, ZeroZero);
|
||||
|
||||
Constant *EntriesB = Constant::getNullValue(PointerType::getUnqual(C));
|
||||
Constant *EntriesE = Constant::getNullValue(PointerType::getUnqual(C));
|
||||
static constexpr uint16_t BinDescStructVersion = 1;
|
||||
Constant *DescInit = ConstantStruct::get(
|
||||
SyclBinDescTy,
|
||||
ConstantInt::get(Type::getInt16Ty(C), BinDescStructVersion),
|
||||
ConstantInt::get(Type::getInt16Ty(C), WrappedImages.size()), ImagesB,
|
||||
EntriesB, EntriesE);
|
||||
|
||||
return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, DescInit,
|
||||
Twine(OffloadKindTag) + "descriptor");
|
||||
}
|
||||
|
||||
Module &M;
|
||||
LLVMContext &C;
|
||||
SYCLJITOptions Options;
|
||||
|
||||
StructType *EntryTy = nullptr;
|
||||
StructType *SyclDeviceImageTy = nullptr;
|
||||
StructType *SyclBinDescTy = nullptr;
|
||||
}; // end of SYCLWrapper
|
||||
|
||||
} // namespace
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user