blob: d0e8786c274b523787ec5f4d1c878fe42217df0d [file] [log] [blame]
// Copyright 2021 The IREE Authors
//
// Licensed 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
#include "compiler/plugins/target/LLVMCPU/LibraryBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
// =============================================================================
//
// NOTE: these structures model 1:1 those in iree/hal/local/executable_library.h
//
// This file must always track the latest version. Backwards compatibility with
// existing runtimes using older versions of the header is maintained by
// emitting variants of the structs matching those in the older headers and
// selecting between them in the query function based on the requested version.
//
// =============================================================================
namespace mlir::iree_compiler::IREE::HAL {
static inline int64_t roundUpToAlignment(int64_t value, int64_t alignment) {
return (value + (alignment - 1)) & ~(alignment - 1);
}
//===----------------------------------------------------------------------===//
// iree/hal/local/executable_library.h structure types
//===----------------------------------------------------------------------===//
// The IR snippets below were pulled from clang running with `-S -emit-llvm`
// on the executable_library.h header: https://godbolt.org/z/6bMv5jfvf
// %struct.iree_hal_executable_import_table_v0_t = type {
// i32,
// i8**
// }
static llvm::StructType *makeImportTableType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_import_table_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *type =
llvm::StructType::create(context,
{
i32Type,
llvm::PointerType::get(i8PtrType, 0),
},
"iree_hal_executable_import_table_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_environment_v0_t = type {
// ...
// }
static llvm::StructType *makeEnvironmentType(llvm::LLVMContext &context) {
auto *type = llvm::StructType::getTypeByName(
context, "iree_hal_executable_environment_v0_t");
if (!type) {
type = llvm::StructType::create(context,
"iree_hal_executable_environment_v0_t");
}
return type;
}
// %struct.iree_hal_executable_dispatch_state_v0_t = type {
// ...
// }
static llvm::StructType *makeDispatchStateType(llvm::LLVMContext &context) {
auto *type = llvm::StructType::getTypeByName(
context, "iree_hal_executable_dispatch_state_v0_t");
if (!type) {
type = llvm::StructType::create(context,
"iree_hal_executable_dispatch_state_v0_t");
}
return type;
}
// %struct.iree_hal_executable_workgroup_state_v0_t = type {
// ...
// }
static llvm::StructType *makeWorkgroupStateType(llvm::LLVMContext &context) {
auto *type = llvm::StructType::getTypeByName(
context, "iree_hal_executable_workgroup_state_v0_t");
if (!type) {
type = llvm::StructType::create(context,
"iree_hal_executable_workgroup_state_v0_t");
}
return type;
}
// i32 (%struct.iree_hal_executable_environment_v0_t*,
// %struct.iree_hal_executable_dispatch_state_v0_t*,
// i8*)
static llvm::FunctionType *
makeDispatchFunctionType(llvm::LLVMContext &context) {
auto *environmentType = makeEnvironmentType(context);
auto *dispatchStateType = makeDispatchStateType(context);
auto *workgroupStateType = makeWorkgroupStateType(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
return llvm::FunctionType::get(
i32Type,
{
llvm::PointerType::get(environmentType, 0),
llvm::PointerType::get(dispatchStateType, 0),
llvm::PointerType::get(workgroupStateType, 0),
},
/*isVarArg=*/false);
}
// %struct.iree_hal_executable_dispatch_attrs_v0_t = type {
// i16,
// i8,
// i8,
// i32,
// i64[8]
// }
static llvm::StructType *makeDispatchAttrsType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_dispatch_attrs_v0_t")) {
return existingType;
}
auto *i8Type = llvm::IntegerType::getInt8Ty(context);
auto *i16Type = llvm::IntegerType::getInt16Ty(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i64Type = llvm::IntegerType::getInt64Ty(context);
auto *type =
llvm::StructType::create(context,
{
i16Type, i8Type, i8Type, i32Type,
i64Type, // [0]
i64Type, // [1]
i64Type, // [2]
i64Type, // [3]
i64Type, // [4]
i64Type, // [5]
i64Type, // [6]
i64Type, // [7]
},
"iree_hal_executable_dispatch_attrs_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_source_location_v0_t = type {
// i32,
// i32,
// i8*
// }
static llvm::StructType *makeSourceLocationType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_source_location_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *type =
llvm::StructType::create(context,
{
i32Type,
i32Type,
i8PtrType,
},
"iree_hal_executable_source_location_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_stage_location_table_v0_t = type {
// i32,
// i8**,
// %struct.iree_hal_executable_source_location_v0_t*,
// }
static llvm::StructType *
makeStageLocationTableType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_stage_location_table_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *sourceLocationType = makeSourceLocationType(context);
auto *type = llvm::StructType::create(
context,
{
i32Type,
llvm::PointerType::get(i8PtrType, 0),
llvm::PointerType::get(sourceLocationType, 0),
},
"iree_hal_executable_stage_location_table_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_export_table_v0_t = type {
// i32,
// i32*,
// %struct.iree_hal_executable_dispatch_attrs_v0_t*,
// i8**,
// i8**,
// %struct.iree_hal_executable_source_location_v0_t*,
// %struct.iree_hal_executable_stage_location_table_v0_t*,
// }
static llvm::StructType *makeExportTableType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_export_table_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *dispatchFunctionType = makeDispatchFunctionType(context);
auto *dispatchFunctionPointerType =
llvm::PointerType::get(dispatchFunctionType, 0);
auto *dispatchAttrsType = makeDispatchAttrsType(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *sourceLocationType = makeSourceLocationType(context);
auto *stageLocationTableType = makeStageLocationTableType(context);
auto *type = llvm::StructType::create(
context,
{
i32Type,
llvm::PointerType::get(dispatchFunctionPointerType, 0),
llvm::PointerType::get(dispatchAttrsType, 0),
llvm::PointerType::get(i8PtrType, 0),
llvm::PointerType::get(i8PtrType, 0),
llvm::PointerType::get(sourceLocationType, 0),
llvm::PointerType::get(stageLocationTableType, 0),
},
"iree_hal_executable_export_table_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_constant_table_v0_t = type {
// i32
// }
static llvm::StructType *makeConstantTableType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_constant_table_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *type =
llvm::StructType::create(context,
{
i32Type,
},
"iree_hal_executable_constant_table_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_source_file_v0_t = type {
// i32,
// i8*,
// i32,
// i8*
// }
static llvm::StructType *makeSourceFileType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_source_file_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *type = llvm::StructType::create(context,
{
i32Type,
i8PtrType,
i32Type,
i8PtrType,
},
"iree_hal_executable_source_file_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_source_file_table_v0_t = type {
// i32,
// %struct.iree_hal_executable_source_file_v0_t*,
// }
static llvm::StructType *makeSourceTableType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_source_file_table_v0_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *sourceFileType = makeSourceFileType(context);
auto *type =
llvm::StructType::create(context,
{
i32Type,
llvm::PointerType::get(sourceFileType, 0),
},
"iree_hal_executable_source_file_table_v0_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_library_header_t = type {
// i32,
// i8*,
// i32,
// i32
// }
static llvm::StructType *makeLibraryHeaderType(llvm::LLVMContext &context) {
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_library_header_t")) {
return existingType;
}
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i8PtrType = llvm::PointerType::getUnqual(context);
auto *type = llvm::StructType::create(context,
{
i32Type,
i8PtrType,
i32Type,
i32Type,
},
"iree_hal_executable_library_header_t",
/*isPacked=*/false);
return type;
}
// %struct.iree_hal_executable_library_v0_t = type {
// %struct.iree_hal_executable_library_header_t*,
// %struct.iree_hal_executable_import_table_v0_t,
// %struct.iree_hal_executable_export_table_v0_t,
// }
static llvm::StructType *makeLibraryType(llvm::StructType *libraryHeaderType) {
auto &context = libraryHeaderType->getContext();
if (auto *existingType = llvm::StructType::getTypeByName(
context, "iree_hal_executable_library_v0_t")) {
return existingType;
}
auto *importTableType = makeImportTableType(context);
auto *exportTableType = makeExportTableType(context);
auto *constantTableType = makeConstantTableType(context);
auto *sourceTableType = makeSourceTableType(context);
auto *type =
llvm::StructType::create(context,
{
llvm::PointerType::get(libraryHeaderType, 0),
importTableType,
exportTableType,
constantTableType,
sourceTableType,
},
"iree_hal_executable_library_v0_t",
/*isPacked=*/false);
return type;
}
//===----------------------------------------------------------------------===//
// IR construction utilities
//===----------------------------------------------------------------------===//
// Creates a global NUL-terminated string constant.
//
// Example:
// @.str.2 = private unnamed_addr constant [6 x i8] c"lib_a\00", align 1
static llvm::Constant *createStringConstant(StringRef value,
llvm::Module *module) {
auto i8Type = llvm::IntegerType::getInt8Ty(module->getContext());
auto i32Type = llvm::IntegerType::getInt32Ty(module->getContext());
auto *stringType = llvm::ArrayType::get(i8Type, value.size() + /*NUL*/ 1);
auto *literal =
llvm::ConstantDataArray::getString(module->getContext(), value);
auto *global = new llvm::GlobalVariable(*module, stringType,
/*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
literal, /*Name=*/"");
global->setAlignment(llvm::MaybeAlign(1));
llvm::Constant *zero = llvm::ConstantInt::get(i32Type, 0);
return llvm::ConstantExpr::getInBoundsGetElementPtr(
stringType, global, ArrayRef<llvm::Constant *>{zero, zero});
}
// Creates a global NUL-terminated string constant or NULL if the string is
// empty.
static llvm::Constant *createStringConstantOrNull(StringRef value,
llvm::Module *module) {
if (value.empty()) {
auto i8Type = llvm::IntegerType::getInt8Ty(module->getContext());
return llvm::ConstantPointerNull::get(llvm::PointerType::get(i8Type, 0));
}
return createStringConstant(value, module);
}
// Creates a global serialized buffer constant (or string without NUL).
//
// Example:
// @.data = private unnamed_addr constant [5 x i8] c"lib_a", align 1
static llvm::Constant *createBufferConstant(StringRef name,
ArrayRef<char> value,
llvm::Module *module) {
auto i8Type = llvm::IntegerType::getInt8Ty(module->getContext());
auto i32Type = llvm::IntegerType::getInt32Ty(module->getContext());
auto *bufferType = llvm::ArrayType::get(i8Type, value.size());
auto *literal = llvm::ConstantDataArray::get(module->getContext(), value);
auto *global = new llvm::GlobalVariable(
*module, bufferType,
/*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, literal, name);
global->setAlignment(llvm::MaybeAlign(1));
llvm::Constant *zero = llvm::ConstantInt::get(i32Type, 0);
return llvm::ConstantExpr::getInBoundsGetElementPtr(
bufferType, global, ArrayRef<llvm::Constant *>{zero, zero});
}
// Creates a global constant with the given elements.
static llvm::Constant *createArrayConstant(StringRef name,
llvm::Type *elementType,
ArrayRef<llvm::Constant *> elements,
llvm::Module *module) {
auto *i32Type = llvm::IntegerType::getInt32Ty(module->getContext());
llvm::Constant *zero = llvm::ConstantInt::get(i32Type, 0);
auto *arrayType = llvm::ArrayType::get(elementType, elements.size());
auto *global = new llvm::GlobalVariable(
*module, arrayType, /*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
llvm::ConstantArray::get(arrayType, elements), name);
return llvm::ConstantExpr::getInBoundsGetElementPtr(
arrayType, global, ArrayRef<llvm::Constant *>{zero, zero});
}
//===----------------------------------------------------------------------===//
// Builder interface
//===----------------------------------------------------------------------===//
llvm::Function *LibraryBuilder::build(StringRef queryFuncName) {
auto &context = module->getContext();
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *environmentStructType = makeEnvironmentType(context);
auto *environmentType = llvm::PointerType::get(environmentStructType, 0);
auto *libraryHeaderType = makeLibraryHeaderType(context);
// %struct.iree_hal_executable_library_header_t**
// @iree_hal_library_query(i32, %struct.iree_hal_executable_environment_v0_t*)
auto *queryFuncType =
llvm::FunctionType::get(llvm::PointerType::get(libraryHeaderType, 0),
{
i32Type,
environmentType,
},
/*isVarArg=*/false);
auto *func =
llvm::Function::Create(queryFuncType, llvm::GlobalValue::InternalLinkage,
queryFuncName, *module);
auto *entryBlock = llvm::BasicBlock::Create(context, "entry", func);
llvm::IRBuilder<> builder(entryBlock);
// Build out the header for each version and select it at runtime.
// NOTE: today there is just one version so this is rather simple:
// return max_version == 0 ? &library : NULL;
auto *v0 = buildLibraryV0((queryFuncName + "_v0").str());
builder.CreateRet(builder.CreateSelect(
builder.CreateICmpEQ(func->getArg(0),
llvm::ConstantInt::get(
i32Type, static_cast<int64_t>(Version::LATEST))),
builder.CreatePointerCast(v0,
llvm::PointerType::get(libraryHeaderType, 0)),
llvm::ConstantPointerNull::get(
llvm::PointerType::get(libraryHeaderType, 0))));
return func;
}
llvm::Constant *
LibraryBuilder::buildLibraryV0ImportTable(std::string libraryName) {
auto &context = module->getContext();
auto *importTableType = makeImportTableType(context);
auto *i8Type = llvm::IntegerType::getInt8Ty(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
llvm::Constant *symbolNames =
llvm::Constant::getNullValue(llvm::PointerType::get(i8Type, 0));
if (!imports.empty()) {
SmallVector<llvm::Constant *> symbolNameValues;
for (auto &import : imports) {
auto symbolName = import.symbol_name;
if (import.weak)
symbolName = "?" + symbolName;
symbolNameValues.push_back(createStringConstant(symbolName, module));
}
symbolNames = createArrayConstant(libraryName + "_import_names",
llvm::PointerType::get(i8Type, 0),
symbolNameValues, module);
}
return llvm::ConstantStruct::get(
importTableType, {
// count=
llvm::ConstantInt::get(i32Type, imports.size()),
// symbols=
symbolNames,
});
}
llvm::Constant *
LibraryBuilder::buildLibraryV0ExportTable(std::string libraryName) {
auto &context = module->getContext();
auto *exportTableType = makeExportTableType(context);
auto *dispatchFunctionType = makeDispatchFunctionType(context);
auto *dispatchAttrsType = makeDispatchAttrsType(context);
auto *sourceLocationType = makeSourceLocationType(context);
auto *stageLocationTableType = makeStageLocationTableType(context);
auto *i8Type = llvm::IntegerType::getInt8Ty(context);
auto *i16Type = llvm::IntegerType::getInt16Ty(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
auto *i64Type = llvm::IntegerType::getInt64Ty(context);
// iree_hal_executable_export_table_v0_t::ptrs
SmallVector<llvm::Constant *> exportPtrValues;
for (auto dispatch : exports)
exportPtrValues.push_back(dispatch.func);
llvm::Constant *exportPtrs = createArrayConstant(
libraryName + "_funcs", llvm::PointerType::get(dispatchFunctionType, 0),
exportPtrValues, module);
// iree_hal_executable_export_table_v0_t::attrs
llvm::Constant *exportAttrs =
llvm::Constant::getNullValue(llvm::PointerType::get(i32Type, 0));
bool hasNonDefaultAttrs = llvm::any_of(exports, [](const auto &dispatch) {
return !dispatch.attrs.isDefault();
});
if (hasNonDefaultAttrs) {
SmallVector<llvm::Constant *> exportAttrValues;
for (auto dispatch : exports) {
exportAttrValues.push_back(llvm::ConstantStruct::get(
dispatchAttrsType,
{
// local_memory_pages=
llvm::ConstantInt::get(
i16Type, roundUpToAlignment(dispatch.attrs.localMemorySize,
kWorkgroupLocalMemoryPageSize) /
kWorkgroupLocalMemoryPageSize),
// constant_count=
llvm::ConstantInt::get(i8Type, dispatch.attrs.constantCount),
// binding_count=
llvm::ConstantInt::get(i8Type, dispatch.attrs.bindingCount),
// reserved_0=
llvm::ConstantInt::get(i32Type, 0),
// reserved_1[0]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[1]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[2]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[3]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[4]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[5]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[6]=
llvm::ConstantInt::get(i64Type, 0),
// reserved_1[7]=
llvm::ConstantInt::get(i64Type, 0),
}));
}
exportAttrs = createArrayConstant(libraryName + "_attrs", dispatchAttrsType,
exportAttrValues, module);
}
// iree_hal_executable_export_table_v0_t::names
llvm::Constant *exportNames =
llvm::Constant::getNullValue(llvm::PointerType::get(i8Type, 0));
if (mode == Mode::INCLUDE_REFLECTION_ATTRS) {
SmallVector<llvm::Constant *> exportNameValues;
for (auto dispatch : exports)
exportNameValues.push_back(createStringConstant(dispatch.name, module));
exportNames = createArrayConstant(libraryName + "_names",
llvm::PointerType::get(i8Type, 0),
exportNameValues, module);
}
// iree_hal_executable_export_table_v0_t::tags
auto *i8PtrType = llvm::PointerType::get(i8Type, 0);
llvm::Constant *exportTags =
llvm::Constant::getNullValue(llvm::PointerType::get(i8PtrType, 0));
bool hasAnyTags = llvm::any_of(
exports, [](auto &dispatch) { return !dispatch.tag.empty(); });
if (mode == Mode::INCLUDE_REFLECTION_ATTRS && hasAnyTags) {
SmallVector<llvm::Constant *> exportTagValues;
for (auto dispatch : exports)
exportTagValues.push_back(
createStringConstantOrNull(dispatch.tag, module));
exportTags = createArrayConstant(libraryName + "_tags",
llvm::PointerType::get(i8Type, 0),
exportTagValues, module);
}
// iree_hal_executable_export_table_v0_t::source_locations
llvm::Constant *exportSourceLocations = llvm::Constant::getNullValue(
llvm::PointerType::get(sourceLocationType, 0));
if (mode == Mode::INCLUDE_REFLECTION_ATTRS) {
SmallVector<llvm::Constant *> exportSourceLocationValues;
for (auto dispatch : exports) {
exportSourceLocationValues.push_back(llvm::ConstantStruct::get(
sourceLocationType,
{
// line=
llvm::ConstantInt::get(i32Type, dispatch.sourceLocation.line),
// path_length=
llvm::ConstantInt::get(i32Type,
dispatch.sourceLocation.path.size()),
// path=
createStringConstant(dispatch.sourceLocation.path, module),
}));
}
exportSourceLocations = createArrayConstant(
libraryName + "_source_locations", sourceLocationType,
exportSourceLocationValues, module);
}
// iree_hal_executable_export_table_v0_t::stage_locations
llvm::Constant *exportStageLocations = llvm::Constant::getNullValue(
llvm::PointerType::get(stageLocationTableType, 0));
if (mode == Mode::INCLUDE_REFLECTION_ATTRS) {
SmallVector<llvm::Constant *> exportStageTableValues;
for (auto dispatch : exports) {
SmallVector<llvm::Constant *> exportStageNameValues;
SmallVector<llvm::Constant *> exportSourceLocationValues;
for (auto &stageLocation : dispatch.stageLocations) {
exportStageNameValues.push_back(
createStringConstant(stageLocation.stage, module));
exportSourceLocationValues.push_back(llvm::ConstantStruct::get(
sourceLocationType,
{
// line=
llvm::ConstantInt::get(i32Type, stageLocation.line),
// path_length=
llvm::ConstantInt::get(i32Type, stageLocation.path.size()),
// path=
createStringConstant(stageLocation.path, module),
}));
}
llvm::Constant *stageNamesPtr = createArrayConstant(
libraryName + "_" + dispatch.name + "_stage_names",
llvm::PointerType::get(i8Type, 0), exportStageNameValues, module);
llvm::Constant *sourceLocationsPtr = createArrayConstant(
libraryName + "_" + dispatch.name + "_stage_source_locations",
sourceLocationType, exportSourceLocationValues, module);
exportStageTableValues.push_back(llvm::ConstantStruct::get(
stageLocationTableType,
{
// count=
llvm::ConstantInt::get(i32Type, exportStageNameValues.size()),
// names=
stageNamesPtr,
// locations=
sourceLocationsPtr,
}));
}
if (!exportStageTableValues.empty()) {
exportStageLocations = createArrayConstant(
libraryName + "_stage_location_tables", stageLocationTableType,
exportStageTableValues, module);
}
}
return llvm::ConstantStruct::get(
exportTableType, {
// count=
llvm::ConstantInt::get(i32Type, exports.size()),
// ptrs=
exportPtrs,
// attrs=
exportAttrs,
// names=
exportNames,
// tags=
exportTags,
// source_locations=
exportSourceLocations,
// stage_locations=
exportStageLocations,
});
}
llvm::Constant *
LibraryBuilder::buildLibraryV0ConstantTable(std::string libraryName) {
auto &context = module->getContext();
auto *constantTableType = makeConstantTableType(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
return llvm::ConstantStruct::get(
constantTableType, {
// count=
llvm::ConstantInt::get(i32Type, constantCount),
});
}
llvm::Constant *
LibraryBuilder::buildLibraryV0SourceTable(std::string libraryName) {
auto &context = module->getContext();
auto *sourceFileType = makeSourceFileType(context);
auto *sourceTableType = makeSourceTableType(context);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
llvm::Constant *sourceFilesValue =
llvm::Constant::getNullValue(llvm::PointerType::get(sourceFileType, 0));
if (!sourceFiles.empty()) {
SmallVector<llvm::Constant *> sourceFileValues;
for (auto &sourceFile : sourceFiles) {
sourceFileValues.push_back(llvm::ConstantStruct::get(
sourceFileType,
{
// path_length=
llvm::ConstantInt::get(i32Type, sourceFile.path.size()),
// path=
createStringConstant(sourceFile.path, module),
// content_length=
llvm::ConstantInt::get(i32Type, sourceFile.contents.size()),
// content=
createBufferConstant(sourceFile.path, sourceFile.contents,
module),
}));
}
sourceFilesValue = createArrayConstant(
libraryName + "_sources", sourceFileType, sourceFileValues, module);
}
return llvm::ConstantStruct::get(
sourceTableType, {
// count=
llvm::ConstantInt::get(i32Type, sourceFiles.size()),
// files=
sourceFilesValue,
});
}
llvm::Constant *LibraryBuilder::buildLibraryV0(std::string libraryName) {
auto &context = module->getContext();
auto *libraryHeaderType = makeLibraryHeaderType(context);
auto *libraryType = makeLibraryType(libraryHeaderType);
auto *i32Type = llvm::IntegerType::getInt32Ty(context);
// ----- Header -----
auto *libraryHeader = new llvm::GlobalVariable(
*module, libraryHeaderType, /*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
llvm::ConstantStruct::get(
libraryHeaderType,
{
// version=
llvm::ConstantInt::get(i32Type,
static_cast<int64_t>(Version::LATEST)),
// name=
createStringConstant(module->getName(), module),
// features=
llvm::ConstantInt::get(i32Type, static_cast<int64_t>(features)),
// sanitizer=
llvm::ConstantInt::get(i32Type,
static_cast<int64_t>(sanitizerKind)),
}),
/*Name=*/libraryName + "_header");
// TODO(benvanik): force alignment (8? natural pointer width?)
// ----- Library -----
auto *library = new llvm::GlobalVariable(
*module, libraryType, /*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
llvm::ConstantStruct::get(libraryType,
{
// header=
libraryHeader,
// imports=
buildLibraryV0ImportTable(libraryName),
// exports=
buildLibraryV0ExportTable(libraryName),
// constants=
buildLibraryV0ConstantTable(libraryName),
// sources=
buildLibraryV0SourceTable(libraryName),
}),
/*Name=*/libraryName);
// TODO(benvanik): force alignment (8? natural pointer width?)
return library;
}
} // namespace mlir::iree_compiler::IREE::HAL