14d295cf5SChristian Sigg //===- SerializeToBlob.cpp - MLIR GPU lowering pass -----------------------===//
24d295cf5SChristian Sigg //
34d295cf5SChristian Sigg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d295cf5SChristian Sigg // See https://llvm.org/LICENSE.txt for license information.
54d295cf5SChristian Sigg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d295cf5SChristian Sigg //
74d295cf5SChristian Sigg //===----------------------------------------------------------------------===//
84d295cf5SChristian Sigg //
94d295cf5SChristian Sigg // This file implements a base class for a pass to serialize a gpu module
104d295cf5SChristian Sigg // into a binary blob that can be executed on a GPU. The binary blob is added
114d295cf5SChristian Sigg // as a string attribute to the gpu module.
124d295cf5SChristian Sigg //
134d295cf5SChristian Sigg //===----------------------------------------------------------------------===//
144d295cf5SChristian Sigg 
15d7ef488bSMogball #include "mlir/Dialect/GPU/Transforms/Passes.h"
164d295cf5SChristian Sigg #include "mlir/Pass/Pass.h"
172224221fSChristian Sigg #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
182224221fSChristian Sigg #include "mlir/Target/LLVMIR/Export.h"
194d295cf5SChristian Sigg #include "llvm/IR/LegacyPassManager.h"
2089b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
214d295cf5SChristian Sigg #include "llvm/Support/TargetSelect.h"
224d295cf5SChristian Sigg #include "llvm/Target/TargetMachine.h"
234d295cf5SChristian Sigg 
2440aef79dSKrzysztof Drewniak #include <string>
2540aef79dSKrzysztof Drewniak 
2640aef79dSKrzysztof Drewniak #define DEBUG_TYPE "serialize-to-blob"
2740aef79dSKrzysztof Drewniak 
284d295cf5SChristian Sigg using namespace mlir;
294d295cf5SChristian Sigg 
getDefaultGpuBinaryAnnotation()304d295cf5SChristian Sigg std::string gpu::getDefaultGpuBinaryAnnotation() { return "gpu.binary"; }
314d295cf5SChristian Sigg 
SerializeToBlobPass(TypeID passID)324d295cf5SChristian Sigg gpu::SerializeToBlobPass::SerializeToBlobPass(TypeID passID)
334d295cf5SChristian Sigg     : OperationPass<gpu::GPUModuleOp>(passID) {}
344d295cf5SChristian Sigg 
SerializeToBlobPass(const SerializeToBlobPass & other)354d295cf5SChristian Sigg gpu::SerializeToBlobPass::SerializeToBlobPass(const SerializeToBlobPass &other)
366a291ed0SChristian Sigg     : OperationPass<gpu::GPUModuleOp>(other) {}
374d295cf5SChristian Sigg 
38bd22554aSKrzysztof Drewniak Optional<std::string>
translateToISA(llvm::Module & llvmModule,llvm::TargetMachine & targetMachine)39bd22554aSKrzysztof Drewniak gpu::SerializeToBlobPass::translateToISA(llvm::Module &llvmModule,
404d295cf5SChristian Sigg                                          llvm::TargetMachine &targetMachine) {
414d295cf5SChristian Sigg   llvmModule.setDataLayout(targetMachine.createDataLayout());
424d295cf5SChristian Sigg 
43bd22554aSKrzysztof Drewniak   if (failed(optimizeLlvm(llvmModule, targetMachine)))
44bd22554aSKrzysztof Drewniak     return llvm::None;
45bd22554aSKrzysztof Drewniak 
464d295cf5SChristian Sigg   std::string targetISA;
474d295cf5SChristian Sigg   llvm::raw_string_ostream stream(targetISA);
48bd22554aSKrzysztof Drewniak 
49bd22554aSKrzysztof Drewniak   { // Drop pstream after this to prevent the ISA from being stuck buffering
50bd22554aSKrzysztof Drewniak     llvm::buffer_ostream pstream(stream);
51d729f4c3Srdzhabarov     llvm::legacy::PassManager codegenPasses;
52d729f4c3Srdzhabarov 
53bd22554aSKrzysztof Drewniak     if (targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,
54bd22554aSKrzysztof Drewniak                                           llvm::CGFT_AssemblyFile))
55bd22554aSKrzysztof Drewniak       return llvm::None;
56bd22554aSKrzysztof Drewniak 
574d295cf5SChristian Sigg     codegenPasses.run(llvmModule);
58bd22554aSKrzysztof Drewniak   }
59bd22554aSKrzysztof Drewniak   return stream.str();
604d295cf5SChristian Sigg }
614d295cf5SChristian Sigg 
runOnOperation()624d295cf5SChristian Sigg void gpu::SerializeToBlobPass::runOnOperation() {
634d295cf5SChristian Sigg   // Lower the module to an LLVM IR module using a separate context to enable
644d295cf5SChristian Sigg   // multi-threaded processing.
654d295cf5SChristian Sigg   llvm::LLVMContext llvmContext;
664d295cf5SChristian Sigg   std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext);
674d295cf5SChristian Sigg   if (!llvmModule)
684d295cf5SChristian Sigg     return signalPassFailure();
694d295cf5SChristian Sigg 
704d295cf5SChristian Sigg   // Lower the LLVM IR module to target ISA.
714d295cf5SChristian Sigg   std::unique_ptr<llvm::TargetMachine> targetMachine = createTargetMachine();
724d295cf5SChristian Sigg   if (!targetMachine)
734d295cf5SChristian Sigg     return signalPassFailure();
744d295cf5SChristian Sigg 
75bd22554aSKrzysztof Drewniak   Optional<std::string> maybeTargetISA =
76bd22554aSKrzysztof Drewniak       translateToISA(*llvmModule, *targetMachine);
77bd22554aSKrzysztof Drewniak 
78491d2701SKazu Hirata   if (!maybeTargetISA.has_value())
79bd22554aSKrzysztof Drewniak     return signalPassFailure();
80bd22554aSKrzysztof Drewniak 
81*c27d8152SKazu Hirata   std::string targetISA = std::move(maybeTargetISA.value());
824d295cf5SChristian Sigg 
8340aef79dSKrzysztof Drewniak   LLVM_DEBUG({
8440aef79dSKrzysztof Drewniak     llvm::dbgs() << "ISA for module: " << getOperation().getNameAttr() << "\n";
8540aef79dSKrzysztof Drewniak     llvm::dbgs() << targetISA << "\n";
8640aef79dSKrzysztof Drewniak     llvm::dbgs().flush();
8740aef79dSKrzysztof Drewniak   });
8840aef79dSKrzysztof Drewniak 
894d295cf5SChristian Sigg   // Serialize the target ISA.
904d295cf5SChristian Sigg   std::unique_ptr<std::vector<char>> blob = serializeISA(targetISA);
914d295cf5SChristian Sigg   if (!blob)
924d295cf5SChristian Sigg     return signalPassFailure();
934d295cf5SChristian Sigg 
944d295cf5SChristian Sigg   // Add the blob as module attribute.
9592a79dbeSChris Lattner   auto attr =
9692a79dbeSChris Lattner       StringAttr::get(&getContext(), StringRef(blob->data(), blob->size()));
974d295cf5SChristian Sigg   getOperation()->setAttr(gpuBinaryAnnotation, attr);
984d295cf5SChristian Sigg }
994d295cf5SChristian Sigg 
100bd22554aSKrzysztof Drewniak LogicalResult
optimizeLlvm(llvm::Module & llvmModule,llvm::TargetMachine & targetMachine)101bd22554aSKrzysztof Drewniak gpu::SerializeToBlobPass::optimizeLlvm(llvm::Module &llvmModule,
102bd22554aSKrzysztof Drewniak                                        llvm::TargetMachine &targetMachine) {
103bd22554aSKrzysztof Drewniak   // TODO: If serializeToCubin ends up defining optimizations, factor them
104bd22554aSKrzysztof Drewniak   // into here from SerializeToHsaco
105bd22554aSKrzysztof Drewniak   return success();
106bd22554aSKrzysztof Drewniak }
107bd22554aSKrzysztof Drewniak 
getDependentDialects(DialectRegistry & registry) const1082224221fSChristian Sigg void gpu::SerializeToBlobPass::getDependentDialects(
1092224221fSChristian Sigg     DialectRegistry &registry) const {
1102224221fSChristian Sigg   registerLLVMDialectTranslation(registry);
1112224221fSChristian Sigg   OperationPass<gpu::GPUModuleOp>::getDependentDialects(registry);
1122224221fSChristian Sigg }
1132224221fSChristian Sigg 
1144d295cf5SChristian Sigg std::unique_ptr<llvm::TargetMachine>
createTargetMachine()1154d295cf5SChristian Sigg gpu::SerializeToBlobPass::createTargetMachine() {
1164d295cf5SChristian Sigg   Location loc = getOperation().getLoc();
1174d295cf5SChristian Sigg   std::string error;
1184d295cf5SChristian Sigg   const llvm::Target *target =
1194d295cf5SChristian Sigg       llvm::TargetRegistry::lookupTarget(triple, error);
1204d295cf5SChristian Sigg   if (!target) {
1214d295cf5SChristian Sigg     emitError(loc, Twine("failed to lookup target: ") + error);
1224d295cf5SChristian Sigg     return {};
1234d295cf5SChristian Sigg   }
1244d295cf5SChristian Sigg   llvm::TargetMachine *machine =
1254d295cf5SChristian Sigg       target->createTargetMachine(triple, chip, features, {}, {});
1264d295cf5SChristian Sigg   if (!machine) {
1274d295cf5SChristian Sigg     emitError(loc, "failed to create target machine");
1284d295cf5SChristian Sigg     return {};
1294d295cf5SChristian Sigg   }
1304d295cf5SChristian Sigg 
1314d295cf5SChristian Sigg   return std::unique_ptr<llvm::TargetMachine>{machine};
1324d295cf5SChristian Sigg }
1332224221fSChristian Sigg 
1342224221fSChristian Sigg std::unique_ptr<llvm::Module>
translateToLLVMIR(llvm::LLVMContext & llvmContext)1352224221fSChristian Sigg gpu::SerializeToBlobPass::translateToLLVMIR(llvm::LLVMContext &llvmContext) {
1362224221fSChristian Sigg   return translateModuleToLLVMIR(getOperation(), llvmContext,
1372224221fSChristian Sigg                                  "LLVMDialectModule");
1382224221fSChristian Sigg }
139