30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/FormatVariadic.h"
35#define GEN_PASS_DEF_LOWERHOSTCODETOLLVMPASS
36#include "mlir/Conversion/Passes.h.inc"
53 return *op.getBinding();
59 LLVM::MemcpyOp::create(builder, loc, dst, src, size,
false);
69 StringRef kernelModuleName) {
70 return llvm::formatv(
"{0}_{1}_descriptor_set{2}_binding{3}",
71 kernelModuleName.str(), op.getSymName().str(),
72 std::to_string(*op.getDescriptorSet()),
73 std::to_string(*op.getBinding()));
79 return op.getDescriptorSetAttr() && op.getBindingAttr();
87 spirv::ModuleOp module,
89 auto entryPoints =
module.getOps<spirv::EntryPointOp>();
90 if (!llvm::hasSingleElement(entryPoints)) {
91 return module.emitError(
92 "The module must contain exactly one entry point function");
94 auto globalVariables =
module.getOps<spirv::GlobalVariableOp>();
95 for (
auto globalOp : globalVariables) {
105 StringRef spvModuleName =
module.getSymName().value_or(kSPIRVModule);
110 auto entryPoints =
module.getOps<spirv::EntryPointOp>();
111 if (!llvm::hasSingleElement(entryPoints)) {
112 return module.emitError(
113 "The module must contain exactly one entry point function");
115 spirv::EntryPointOp entryPoint = *entryPoints.begin();
116 StringRef funcName = entryPoint.getFn();
117 auto funcOp =
module.lookupSymbol<spirv::FuncOp>(entryPoint.getFnAttr());
118 StringAttr newFuncName =
119 StringAttr::get(module->getContext(), spvModuleName +
"_" + funcName);
144 using ConvertOpToLLVMPattern<gpu::LaunchFuncOp>::ConvertOpToLLVMPattern;
147 matchAndRewrite(gpu::LaunchFuncOp launchOp, OpAdaptor adaptor,
148 ConversionPatternRewriter &rewriter)
const override {
149 auto *op = launchOp.getOperation();
150 MLIRContext *context = rewriter.getContext();
151 auto module = launchOp->getParentOfType<ModuleOp>();
157 StringRef kernelModuleName = launchOp.getKernelModuleName().getValue();
158 std::string spvModuleName =
kSPIRVModule + kernelModuleName.str();
159 auto spvModule =
module.lookupSymbol<spirv::ModuleOp>(
160 StringAttr::get(context, spvModuleName));
162 return launchOp.emitOpError(
"SPIR-V kernel module '")
163 << spvModuleName <<
"' is not found";
172 StringRef kernelFuncName = launchOp.getKernelName().getValue();
173 std::string newKernelFuncName = spvModuleName +
"_" + kernelFuncName.str();
174 auto kernelFunc =
module.lookupSymbol<LLVM::LLVMFuncOp>(
175 StringAttr::get(context, newKernelFuncName));
177 OpBuilder::InsertionGuard guard(rewriter);
178 rewriter.setInsertionPointToStart(module.getBody());
179 kernelFunc = LLVM::LLVMFuncOp::create(
180 rewriter, rewriter.getUnknownLoc(), newKernelFuncName,
181 LLVM::LLVMFunctionType::get(LLVM::LLVMVoidType::get(context),
183 rewriter.setInsertionPoint(launchOp);
187 DenseMap<uint32_t, spirv::GlobalVariableOp> globalVariableMap;
193 Location loc = launchOp.getLoc();
194 SmallVector<CopyInfo, 4> copyInfo;
195 auto numKernelOperands = launchOp.getNumKernelOperands();
196 auto kernelOperands = adaptor.getOperands().take_back(numKernelOperands);
197 for (
const auto &operand : llvm::enumerate(kernelOperands)) {
199 auto memRefType = dyn_cast<MemRefType>(
200 launchOp.getKernelOperand(operand.index()).getType());
206 SmallVector<Value, 4> sizes;
207 SmallVector<Value, 4> strides;
209 getMemRefDescriptorSizes(loc, memRefType, {}, rewriter, sizes, strides,
211 MemRefDescriptor descriptor(operand.value());
212 Value src = descriptor.allocatedPtr(rewriter, loc);
217 spirv::GlobalVariableOp spirvGlobal = globalVariableMap[operand.index()];
219 cast<spirv::PointerType>(spirvGlobal.getType()).getPointeeType();
220 auto dstGlobalType = typeConverter->convertType(pointeeType);
226 auto dstGlobal =
module.lookupSymbol<LLVM::GlobalOp>(name);
228 OpBuilder::InsertionGuard guard(rewriter);
229 rewriter.setInsertionPointToStart(module.getBody());
230 dstGlobal = LLVM::GlobalOp::create(
231 rewriter, loc, dstGlobalType,
232 false, LLVM::Linkage::Linkonce, name, Attribute(),
234 rewriter.setInsertionPoint(launchOp);
240 Value dst = LLVM::AddressOfOp::create(
241 rewriter, loc, typeConverter->convertType(spirvGlobal.getType()),
242 dstGlobal.getSymName());
243 copy(loc, dst, src, sizeBytes, rewriter);
248 info.size = sizeBytes;
249 copyInfo.push_back(info);
252 rewriter.replaceOpWithNewOp<LLVM::CallOp>(op, kernelFunc,
254 for (CopyInfo info : copyInfo)
255 copy(loc, info.src, info.dst, info.size, rewriter);
260class LowerHostCodeToLLVM
265 void runOnOperation()
override {
266 ModuleOp module = getOperation();
269 for (
auto gpuModule :
270 llvm::make_early_inc_range(module.getOps<gpu::GPUModuleOp>()))
274 for (
auto func : module.getOps<func::FuncOp>()) {
275 func->setDiscardableAttr(LLVM::LLVMDialect::getEmitCWrapperAttrName(),
280 LowerToLLVMOptions
options(module.getContext());
282 auto *context =
module.getContext();
283 RewritePatternSet patterns(context);
284 LLVMTypeConverter typeConverter(context,
options);
288 patterns.add<GPULaunchLowering>(typeConverter);
294 ConversionTarget
target(*context);
295 target.addLegalDialect<LLVM::LLVMDialect>();
296 if (
failed(applyPartialConversion(module,
target, std::move(patterns))))
301 for (
auto spvModule : module.getOps<spirv::ModuleOp>()) {
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static constexpr const char kSPIRVModule[]
static std::string createGlobalVariableWithBindName(spirv::GlobalVariableOp op, StringRef kernelModuleName)
Encodes the binding and descriptor set numbers into a new symbolic name.
static unsigned calculateGlobalIndex(spirv::GlobalVariableOp op)
Calculates the index of the kernel's operand that is represented by the given global variable with th...
static LogicalResult encodeKernelName(spirv::ModuleOp module)
Encodes the SPIR-V module's symbolic name into the name of the entry point function.
static LogicalResult getKernelGlobalVariables(spirv::ModuleOp module, DenseMap< uint32_t, spirv::GlobalVariableOp > &globalVariableMap)
Fills globalVariableMap with SPIR-V global variables that represent kernel arguments from the given S...
static bool hasDescriptorSetAndBinding(spirv::GlobalVariableOp op)
Returns true if the given global variable has both a descriptor set number and a binding number.
static constexpr const char kSPIRVModule[]
static llvm::ManagedStatic< PassManagerOptions > options
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
static LogicalResult replaceAllSymbolUses(StringAttr oldSymbol, StringAttr newSymbol, Operation *from)
Attempt to replace all uses of the given symbol 'oldSymbol' with the provided symbol 'newSymbol' that...
static void setSymbolName(Operation *symbol, StringAttr name)
Sets the name of the given symbol operation.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void populateArithToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns)
Include the generated interface declarations.
void populateSPIRVToLLVMTypeConversion(LLVMTypeConverter &typeConverter, spirv::ClientAPI clientAPIForAddressSpaceMapping=spirv::ClientAPI::Unknown)
Populates type conversions with additional SPIR-V types.
void populateFuncToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect the patterns to convert from the Func dialect to LLVM.
void populateFinalizeMemRefToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect a set of patterns to convert memory-related operations from the MemRef dialect to the LLVM di...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap