//===- GPUToROCDLPipeline.cpp - Lowering pipeline to ROCDL/AMDGPU --------===// // // Part of the LLVM Project, 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 // //===----------------------------------------------------------------------===// // // This file implements a sink pipeline that lowers a payload containing // `gpu.launch` / `gpu.module` ops to AMDGPU/ROCDL and emits an AMDGCN binary // blob via `gpu-module-to-binary`. It is the AMD counterpart of // `gpu-lower-to-nvvm-pipeline` and `gpu-lower-to-xevm-pipeline`. // //===----------------------------------------------------------------------===// #include "mlir/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.h" #include "mlir/Conversion/AffineToStandard/AffineToStandard.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h" #include "mlir/Conversion/GPUCommon/GPUCommonPass.h" #include "mlir/Conversion/GPUToROCDL/GPUToROCDLPass.h" #include "mlir/Conversion/GPUToROCDL/Runtimes.h" #include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h" #include "mlir/Conversion/MathToLLVM/MathToLLVM.h" #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h" #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Conversion/VectorToSCF/VectorToSCF.h" #include "mlir/Dialect/GPU/IR/GPUDialect.h" #include "mlir/Dialect/GPU/Pipelines/Passes.h" #include "mlir/Dialect/GPU/Transforms/Passes.h" #include "mlir/Dialect/MemRef/Transforms/Passes.h" #include "mlir/Pass/PassManager.h" #include "mlir/Pass/PassOptions.h" #include "mlir/Transforms/Passes.h" using namespace mlir; namespace { //===----------------------------------------------------------------------===// // Common pipeline //===----------------------------------------------------------------------===// void buildCommonPassPipeline( OpPassManager &pm, const mlir::gpu::GPUToROCDLPipelineOptions &options) { // Lower AMDGPU dialect ops (e.g. amdgpu.lds_barrier, amdgpu.dpp, // amdgpu.mfma, amdgpu.dot, ...) to ROCDL intrinsics first, while they may // still live in unout-lined `gpu.launch` bodies. Mirrors the way NVVM's // pipeline runs `convert-nvgpu-to-nvvm` before kernel outlining. ConvertAMDGPUToROCDLPassOptions amdgpuToROCDLOpt; amdgpuToROCDLOpt.chipset = options.chip; pm.addPass(createConvertAMDGPUToROCDLPass(amdgpuToROCDLOpt)); pm.addPass(createGpuKernelOutliningPass()); pm.addPass(createConvertVectorToSCFPass()); pm.addPass(createSCFToControlFlowPass()); pm.addPass(createConvertFuncToLLVMPass()); pm.addPass(memref::createExpandStridedMetadataPass()); GpuROCDLAttachTargetOptions rocdlTargetOptions; rocdlTargetOptions.triple = options.triple; rocdlTargetOptions.chip = options.chip; rocdlTargetOptions.features = options.features; rocdlTargetOptions.abiVersion = options.abiVersion; rocdlTargetOptions.optLevel = options.optLevel; rocdlTargetOptions.wave64Flag = options.wave64; pm.addPass(createGpuROCDLAttachTarget(rocdlTargetOptions)); pm.addPass(createLowerAffinePass()); pm.addPass(createArithToLLVMConversionPass()); ConvertIndexToLLVMPassOptions convertIndexToLLVMPassOpt; convertIndexToLLVMPassOpt.indexBitwidth = options.indexBitWidth; pm.addPass(createConvertIndexToLLVMPass(convertIndexToLLVMPassOpt)); pm.addPass(createCanonicalizerPass()); pm.addPass(createCSEPass()); } //===----------------------------------------------------------------------===// // GPUModule-specific stuff. //===----------------------------------------------------------------------===// void buildGpuPassPipeline(OpPassManager &pm, const mlir::gpu::GPUToROCDLPipelineOptions &options) { ConvertGpuOpsToROCDLOpsOptions opt; opt.chipset = options.chip; opt.useBarePtrCallConv = options.kernelUseBarePtrCallConv; opt.indexBitwidth = options.indexBitWidth; // Always declare HIP as the runtime so that gpu.printf etc. lower to the // matching runtime entry points exposed by `libmlir_rocm_runtime.so`. opt.runtime = mlir::gpu::amd::Runtime::HIP; pm.addNestedPass(createConvertGpuOpsToROCDLOps(opt)); pm.addNestedPass(createCanonicalizerPass()); pm.addNestedPass(createCSEPass()); pm.addNestedPass(createReconcileUnrealizedCastsPass()); } //===----------------------------------------------------------------------===// // Host Post-GPU pipeline //===----------------------------------------------------------------------===// void buildHostPostPipeline( OpPassManager &pm, const mlir::gpu::GPUToROCDLPipelineOptions &options) { GpuToLLVMConversionPassOptions opt; opt.hostBarePtrCallConv = options.hostUseBarePtrCallConv; opt.kernelBarePtrCallConv = options.kernelUseBarePtrCallConv; pm.addPass(createGpuToLLVMConversionPass(opt)); GpuModuleToBinaryPassOptions gpuModuleToBinaryPassOptions; gpuModuleToBinaryPassOptions.compilationTarget = options.binaryFormat; gpuModuleToBinaryPassOptions.cmdOptions = options.cmdOptions; pm.addPass(createGpuModuleToBinaryPass(gpuModuleToBinaryPassOptions)); pm.addPass(createConvertMathToLLVMPass()); pm.addPass(createCanonicalizerPass()); pm.addPass(createCSEPass()); pm.addPass(createReconcileUnrealizedCastsPass()); } } // namespace void mlir::gpu::buildLowerToROCDLPassPipeline( OpPassManager &pm, const GPUToROCDLPipelineOptions &options) { // Common pipelines buildCommonPassPipeline(pm, options); // GPUModule-specific stuff buildGpuPassPipeline(pm, options); // Host post-GPUModule-specific stuff buildHostPostPipeline(pm, options); } void mlir::gpu::registerGPUToROCDLPipeline() { PassPipelineRegistration( "gpu-lower-to-rocdl-pipeline", "The default pipeline lowers main dialects (arith, memref, scf, vector, " "gpu) to ROCDL. It starts by lowering GPU code to the specified " "compilation target (default is fatbin) then lowers the host code.", buildLowerToROCDLPassPipeline); }