1 //===- SerializeToBlob.cpp - MLIR GPU lowering pass -----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a base class for a pass to serialize a gpu module 10 // into a binary blob that can be executed on a GPU. The binary blob is added 11 // as a string attribute to the gpu module. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "mlir/Dialect/GPU/Passes.h" 16 #include "mlir/Pass/Pass.h" 17 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" 18 #include "mlir/Target/LLVMIR/Export.h" 19 #include "llvm/IR/LegacyPassManager.h" 20 #include "llvm/Support/TargetRegistry.h" 21 #include "llvm/Support/TargetSelect.h" 22 #include "llvm/Target/TargetMachine.h" 23 24 using namespace mlir; 25 26 std::string gpu::getDefaultGpuBinaryAnnotation() { return "gpu.binary"; } 27 28 gpu::SerializeToBlobPass::SerializeToBlobPass(TypeID passID) 29 : OperationPass<gpu::GPUModuleOp>(passID) {} 30 31 gpu::SerializeToBlobPass::SerializeToBlobPass(const SerializeToBlobPass &other) 32 : OperationPass<gpu::GPUModuleOp>(other) {} 33 34 static std::string translateToISA(llvm::Module &llvmModule, 35 llvm::TargetMachine &targetMachine) { 36 llvmModule.setDataLayout(targetMachine.createDataLayout()); 37 38 std::string targetISA; 39 llvm::raw_string_ostream stream(targetISA); 40 llvm::buffer_ostream pstream(stream); 41 llvm::legacy::PassManager codegenPasses; 42 targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr, 43 llvm::CGFT_AssemblyFile); 44 codegenPasses.run(llvmModule); 45 return targetISA; 46 } 47 48 void gpu::SerializeToBlobPass::runOnOperation() { 49 // Lower the module to an LLVM IR module using a separate context to enable 50 // multi-threaded processing. 51 llvm::LLVMContext llvmContext; 52 std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext); 53 if (!llvmModule) 54 return signalPassFailure(); 55 56 // Lower the LLVM IR module to target ISA. 57 std::unique_ptr<llvm::TargetMachine> targetMachine = createTargetMachine(); 58 if (!targetMachine) 59 return signalPassFailure(); 60 61 std::string targetISA = translateToISA(*llvmModule, *targetMachine); 62 63 // Serialize the target ISA. 64 std::unique_ptr<std::vector<char>> blob = serializeISA(targetISA); 65 if (!blob) 66 return signalPassFailure(); 67 68 // Add the blob as module attribute. 69 auto attr = StringAttr::get(&getContext(), {blob->data(), blob->size()}); 70 getOperation()->setAttr(gpuBinaryAnnotation, attr); 71 } 72 73 void gpu::SerializeToBlobPass::getDependentDialects( 74 DialectRegistry ®istry) const { 75 registerLLVMDialectTranslation(registry); 76 OperationPass<gpu::GPUModuleOp>::getDependentDialects(registry); 77 } 78 79 std::unique_ptr<llvm::TargetMachine> 80 gpu::SerializeToBlobPass::createTargetMachine() { 81 Location loc = getOperation().getLoc(); 82 std::string error; 83 const llvm::Target *target = 84 llvm::TargetRegistry::lookupTarget(triple, error); 85 if (!target) { 86 emitError(loc, Twine("failed to lookup target: ") + error); 87 return {}; 88 } 89 llvm::TargetMachine *machine = 90 target->createTargetMachine(triple, chip, features, {}, {}); 91 if (!machine) { 92 emitError(loc, "failed to create target machine"); 93 return {}; 94 } 95 96 return std::unique_ptr<llvm::TargetMachine>{machine}; 97 } 98 99 std::unique_ptr<llvm::Module> 100 gpu::SerializeToBlobPass::translateToLLVMIR(llvm::LLVMContext &llvmContext) { 101 return translateModuleToLLVMIR(getOperation(), llvmContext, 102 "LLVMDialectModule"); 103 } 104