-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[mlir] Prepare convert-gpu-to-spirv for OpenCL support #69941
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
7ca3f97
02ff96c
561af5d
6417cb7
d73edae
57c0d76
4241a60
7f0efa4
dfb3fcb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
#include "mlir/Conversion/FuncToSPIRV/FuncToSPIRV.h" | ||
#include "mlir/Conversion/GPUToSPIRV/GPUToSPIRV.h" | ||
#include "mlir/Conversion/MemRefToSPIRV/MemRefToSPIRV.h" | ||
#include "mlir/Dialect/Func/IR/FuncOps.h" | ||
#include "mlir/Dialect/GPU/IR/GPUDialect.h" | ||
#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h" | ||
#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h" | ||
|
@@ -54,22 +55,67 @@ void GPUToSPIRVPass::runOnOperation() { | |
|
||
SmallVector<Operation *, 1> gpuModules; | ||
OpBuilder builder(context); | ||
|
||
auto getTargetEnvFromGPUModuleOp = [*this](gpu::GPUModuleOp moduleOp) { | ||
Operation *gpuModule = moduleOp.getOperation(); | ||
auto targetAttr = spirv::lookupTargetEnvOrDefault(gpuModule); | ||
std::unique_ptr<ConversionTarget> target = | ||
SPIRVConversionTarget::get(targetAttr); | ||
|
||
SPIRVConversionOptions options; | ||
options.use64bitIndex = this->use64bitIndex; | ||
SPIRVTypeConverter typeConverter(targetAttr, options); | ||
const spirv::TargetEnv &targetEnv = typeConverter.getTargetEnv(); | ||
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return targetEnv; | ||
}; | ||
|
||
module.walk([&](gpu::GPUModuleOp moduleOp) { | ||
// Clone each GPU kernel module for conversion, given that the GPU | ||
// launch op still needs the original GPU kernel module. | ||
builder.setInsertionPoint(moduleOp.getOperation()); | ||
// SPIRV module insertion point by is after original GPU module. | ||
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// This works fine for Vulkan shader that has a dedicated runner. | ||
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// But OpenCL kernel needs SPIRV module placed inside original GPU module as | ||
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// OpenCL uses GPU compilation pipeline. | ||
const mlir::spirv::TargetEnv &targetEnv = | ||
getTargetEnvFromGPUModuleOp(moduleOp); | ||
FailureOr<spirv::MemoryModel> memoryModel = | ||
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
spirv::getMemoryModel(targetEnv); | ||
if (failed(memoryModel)) | ||
return signalPassFailure(); | ||
if (memoryModel == spirv::MemoryModel::OpenCL) { | ||
builder.setInsertionPoint(moduleOp.getBody(), | ||
moduleOp.getBody()->begin()); | ||
} else { | ||
builder.setInsertionPoint(moduleOp.getOperation()); | ||
} | ||
gpuModules.push_back(builder.clone(*moduleOp.getOperation())); | ||
}); | ||
|
||
// Run conversion for each module independently as they can have different | ||
// TargetEnv attributes. | ||
for (Operation *gpuModule : gpuModules) { | ||
mlir::spirv::TargetEnvAttr targetAttr = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use the lambda function in the above? This is duplicating the logic there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now the lambda returns boolean and cannot be used. Also that line is from the original code. I just moved it up a bit since I needed access to targetAttr before memory space mapping. |
||
spirv::lookupTargetEnvOrDefault(gpuModule); | ||
std::unique_ptr<ConversionTarget> target = | ||
SPIRVConversionTarget::get(targetAttr); | ||
|
||
SPIRVConversionOptions options; | ||
options.use64bitIndex = this->use64bitIndex; | ||
SPIRVTypeConverter typeConverter(targetAttr, options); | ||
const spirv::TargetEnv &targetEnv = typeConverter.getTargetEnv(); | ||
FailureOr<spirv::MemoryModel> memoryModel = | ||
spirv::getMemoryModel(targetEnv); | ||
if (failed(memoryModel)) | ||
return signalPassFailure(); | ||
|
||
// Map MemRef memory space to SPIR-V storage class first if requested. | ||
if (mapMemorySpace) { | ||
std::unique_ptr<ConversionTarget> target = | ||
spirv::getMemorySpaceToStorageClassTarget(*context); | ||
spirv::MemorySpaceToStorageClassMap memorySpaceMap = | ||
spirv::mapMemorySpaceToVulkanStorageClass; | ||
(memoryModel == spirv::MemoryModel::OpenCL) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we can also use the above spirv::MemorySpaceToStorageClassMap memorySpaceMap =
targetEnvSupportsKernelCapability(gpuModule) ? ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
? spirv::mapMemorySpaceToOpenCLStorageClass | ||
: spirv::mapMemorySpaceToVulkanStorageClass; | ||
spirv::MemorySpaceToStorageClassConverter converter(memorySpaceMap); | ||
|
||
RewritePatternSet patterns(context); | ||
|
@@ -79,13 +125,6 @@ void GPUToSPIRVPass::runOnOperation() { | |
return signalPassFailure(); | ||
} | ||
|
||
auto targetAttr = spirv::lookupTargetEnvOrDefault(gpuModule); | ||
std::unique_ptr<ConversionTarget> target = | ||
SPIRVConversionTarget::get(targetAttr); | ||
|
||
SPIRVConversionOptions options; | ||
options.use64bitIndex = this->use64bitIndex; | ||
SPIRVTypeConverter typeConverter(targetAttr, options); | ||
populateMMAToSPIRVCoopMatrixTypeConversion(typeConverter, | ||
this->useCoopMatrixNV); | ||
|
||
|
@@ -108,6 +147,31 @@ void GPUToSPIRVPass::runOnOperation() { | |
if (failed(applyFullConversion(gpuModule, *target, std::move(patterns)))) | ||
return signalPassFailure(); | ||
} | ||
|
||
// In case of OpenCL, gpu.func in original gpu.module needs to replaced with | ||
kuhar marked this conversation as resolved.
Show resolved
Hide resolved
antiagainst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// an empty func.func with same arguments as gpu.func. And it also needs | ||
// gpu.kernel attribute set. | ||
module.walk([&](gpu::GPUModuleOp moduleOp) { | ||
const mlir::spirv::TargetEnv &targetEnv = | ||
getTargetEnvFromGPUModuleOp(moduleOp); | ||
FailureOr<spirv::MemoryModel> memoryModel = | ||
spirv::getMemoryModel(targetEnv); | ||
if (failed(memoryModel)) | ||
return signalPassFailure(); | ||
if (memoryModel == spirv::MemoryModel::OpenCL) { | ||
moduleOp.walk([&](gpu::GPUFuncOp funcOp) { | ||
builder.setInsertionPoint(funcOp); | ||
auto newFuncOp = builder.create<func::FuncOp>( | ||
funcOp.getLoc(), funcOp.getName(), funcOp.getFunctionType()); | ||
auto entryBlock = newFuncOp.addEntryBlock(); | ||
builder.setInsertionPointToEnd(entryBlock); | ||
builder.create<func::ReturnOp>(funcOp.getLoc()); | ||
newFuncOp->setAttr(gpu::GPUDialect::getKernelFuncAttrName(), | ||
builder.getUnitAttr()); | ||
funcOp.erase(); | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
} // namespace | ||
|
Uh oh!
There was an error while loading. Please reload this page.