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/MC/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 = 70 StringAttr::get(&getContext(), StringRef(blob->data(), blob->size())); 71 getOperation()->setAttr(gpuBinaryAnnotation, attr); 72 } 73 74 void gpu::SerializeToBlobPass::getDependentDialects( 75 DialectRegistry ®istry) const { 76 registerLLVMDialectTranslation(registry); 77 OperationPass<gpu::GPUModuleOp>::getDependentDialects(registry); 78 } 79 80 std::unique_ptr<llvm::TargetMachine> 81 gpu::SerializeToBlobPass::createTargetMachine() { 82 Location loc = getOperation().getLoc(); 83 std::string error; 84 const llvm::Target *target = 85 llvm::TargetRegistry::lookupTarget(triple, error); 86 if (!target) { 87 emitError(loc, Twine("failed to lookup target: ") + error); 88 return {}; 89 } 90 llvm::TargetMachine *machine = 91 target->createTargetMachine(triple, chip, features, {}, {}); 92 if (!machine) { 93 emitError(loc, "failed to create target machine"); 94 return {}; 95 } 96 97 return std::unique_ptr<llvm::TargetMachine>{machine}; 98 } 99 100 std::unique_ptr<llvm::Module> 101 gpu::SerializeToBlobPass::translateToLLVMIR(llvm::LLVMContext &llvmContext) { 102 return translateModuleToLLVMIR(getOperation(), llvmContext, 103 "LLVMDialectModule"); 104 } 105