Skip to content

[mlir][spirv] Implement gpu::TargetAttrInterface #69949

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

Merged
merged 7 commits into from
Nov 5, 2023

Conversation

silee2
Copy link
Contributor

@silee2 silee2 commented Oct 23, 2023

Create SPIRV Target Attribute to enable GPU compilation pipeline. The Target Attribute is modeled after the existing spriv.target_env Plan is to use this new attribute to enable GPU compilation pipeline for OpenCL kernels only.
The changes do not impact Vulkan shaders using milr-vulkan-runner. New GPU Dialect transform pass spirv-attach-target is implemented for attaching attribute from CLI.
gpu-module-to-binary pass now works with GPU module that has SPIRV module with OpenCL kernel functions inside.

Create SPIRV Target Attribute to enable GPU compilation pipeline.
The Target Attribute is modeled after the existing spriv.target_env
Plan is to use this new attribute to enable GPU compilation pipeline
for OpenCL kernels only.
The changes do not impact Vulkan shaders using milr-vulkan-runner.
New GPU Dialect transform pass spirv-attach-target is implemented for
attaching attribute from CLI.
gpu-module-to-binary pass now works with GPU module that has SPIRV module
with OpenCL kernel functions inside.
@silee2
Copy link
Contributor Author

silee2 commented Oct 23, 2023

Part of refactoring and breaking down #65539 into smaller PRs.

@silee2
Copy link
Contributor Author

silee2 commented Oct 23, 2023

@fabianmcg Let me know if I'm missing anything. I have one more PR after this one that makes target LLVMIR aware of SPIRV dialect since the new target attribute is part of SPIRV dialect which was not considered a leaf dialect that needs translation to LLVMIR.

@fabianmcg
Copy link
Contributor

fabianmcg commented Oct 23, 2023

@silee2 I'll take a closer look later, at first glance it looks like everything is there.

Just one quick question, can you describe the next PR a bit more? Because you shouldn't need to make the target LLVMIR aware, as the binary embedding is mostly dialect agnostic, so there shouldn't be an issue with SPIRVTargetAttr not having a translation to LLVM.
From what I remember from the original PR the only other modification needed is changing how the kernel is launched, and that change must be done in Target/LLVMIR/Dialect/GPU/SelectObjectAttr.cpp

@fabianmcg fabianmcg self-requested a review October 23, 2023 19:15
}
auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module);
auto spvMods = gpuMod.getOps<spirv::ModuleOp>();
auto spvMod = *spvMods.begin();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A check is necessary before *spvMods.begin(), as spvMods could be an empty range.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added check for empty range.

return std::nullopt;
}

SmallVector<char, 0> spvData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest instead of the loop:

Suggested change
SmallVector<char, 0> spvData;
SmallVector<char, 0> spvData(spvBinary.size() * sizeof(uint32_t), 0);
memcpy(spvData.data(), spvBinary.data(), spvData.size());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed as suggested.

let description = [{
GPU target attribute for controlling compilation of SPIRV targets.
}];
let parameters = (ins
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of all of these parameters? I couldn't find the place where they are being used, are they being used at a later patch, or are they only informational?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those parameters are for describing target environment: https://mlir.llvm.org/docs/Dialects/SPIR-V/#target-environment
The parameters are not used today since lowering to SPIR-V is restricted to common set of SPIR-V ops supported in all environments.
But in the future, lowering passes can check the parameters and utilize SPIR-V extension ops or do target specific optimizations.

@silee2
Copy link
Contributor Author

silee2 commented Oct 26, 2023

@silee2 I'll take a closer look later, at first glance it looks like everything is there.

Just one quick question, can you describe the next PR a bit more? Because you shouldn't need to make the target LLVMIR aware, as the binary embedding is mostly dialect agnostic, so there shouldn't be an issue with SPIRVTargetAttr not having a translation to LLVM. From what I remember from the original PR the only other modification needed is changing how the kernel is launched, and that change must be done in Target/LLVMIR/Dialect/GPU/SelectObjectAttr.cpp

@silee2 silee2 closed this Oct 26, 2023
@silee2 silee2 reopened this Oct 26, 2023
@silee2
Copy link
Contributor Author

silee2 commented Oct 26, 2023

@silee2 I'll take a closer look later, at first glance it looks like everything is there.

Just one quick question, can you describe the next PR a bit more? Because you shouldn't need to make the target LLVMIR aware, as the binary embedding is mostly dialect agnostic, so there shouldn't be an issue with SPIRVTargetAttr not having a translation to LLVM. From what I remember from the original PR the only other modification needed is changing how the kernel is launched, and that change must be done in Target/LLVMIR/Dialect/GPU/SelectObjectAttr.cpp

Yes. SelectObjectAttr.cpp is the only functional change.
But the new target attribute "spirv.target" is part of SPIRV dialect.
And SPIRV dialect becomes a new dialect as part of input to LLVMIR translation.
The additional change updates
mlir/include/mlir/Target/LLVMIR/Dialect/All.h
which now includes
registerSPIRVDialectTranslation(registry);
There are no actual SPIRV ops to translate and just a single attribute type.
So the new files
mlir/include/mlir/Target/LLVMIR/Dialect/SPIRV/SPIRVToLLVMIRTranslation.h
and
mlir/lib/Target/LLVMIR/Dialect/SPIRV/SPIRVToLLVMIRTranslation.cpp
are mostly empty.
Without those changes, mlir-cpu-runner will see spirv.target attribute in the input which is part of SPIRV dialect. And since SPIRV dialect is not registered, mlir-cpu-runner throws an error.
NVVM and ROCDL did not have this issue since NVVM and ROCDL was already registered as an input dialect for LLVMIR translation.

@silee2
Copy link
Contributor Author

silee2 commented Oct 26, 2023

@fabianmcg Can you take a look again? Answered question and addressed change requests.

@fabianmcg
Copy link
Contributor

This patch LGTM! I'll approve once the builds have completed.

Without those changes, mlir-cpu-runner will see spirv.target attribute in the input which is part of SPIRV dialect. And since SPIRV dialect is not registered, mlir-cpu-runner throws an error.

Did you try just registering the dialect instead of adding a translation? I'm still unsure if adding a translation to LLVM is needed, as the error is probably only happening during parsing? But I guess we can have this conversation on the next PR.

@silee2
Copy link
Contributor Author

silee2 commented Oct 26, 2023

check-flang failed on Windows with two unresolved tests. Does not look related to this PR. Merging main again to run CI again.

@silee2
Copy link
Contributor Author

silee2 commented Oct 27, 2023

@joker-eph This PR got approval from @fabianmcg. What do I need to do next to get the PR merged?

@antiagainst
Copy link
Member

Thanks for the contribution and sorry about the delay! I'm getting around to review this pull request (already done a few others). Please wait a bit.

Copy link
Member

@antiagainst antiagainst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for the contribution! A couple of comments inlined. My main concern is the duplication of spirv.target attribute. We should avoid the duplication and confusion there.

@@ -188,4 +188,46 @@ def GpuROCDLAttachTarget: Pass<"rocdl-attach-target", ""> {
];
}

def GpuSPIRVAttachTarget: Pass<"spirv-attach-target", ""> {
let summary = "Attaches an SPIRV target attribute to a GPU Module.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/SPIRV/SPIR-V/.

SPIR-V is the formal spelling. We should use that when in docs and comments.

Also for all the following docs and comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// SPIRV target attribute.
//===----------------------------------------------------------------------===//

def SPIRV_TargetAttr : SPIRV_Attr<"SPIRVTarget", "target"> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute is pretty much a duplication of spirv::TargetEnvAttr defined in SPIRVAttributes.h? We should avoid introducing such duplications and causing confusion. Any reaons we cannot use spirv::TargetEnvAttr directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR to use spirv::TargetEnvAttr.

@@ -0,0 +1,30 @@
//===- Target.h - MLIR SPIRV target registration ----------------*- C++ -*-===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: again, please use SPIR-V in docs and comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -166,4 +166,35 @@ def SPIRV_ResourceLimitsAttr : SPIRV_Attr<"ResourceLimits", "resource_limits"> {
let assemblyFormat = "`<` struct(params) `>`";
}

//===----------------------------------------------------------------------===//
// SPIRV target attribute.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: SPIR-V

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

//
//===----------------------------------------------------------------------===//
//
// This file implements the `GpuSPIRVAttachTarget` pass, attaching
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: GPUSPIRVAttachTarget

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

module->emitError("Module must be a GPU module.");
return std::nullopt;
}
auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move this upward and check whether it's null instead of the isa check at L77.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module);
auto spvMods = gpuMod.getOps<spirv::ModuleOp>();
// Empty spirv::ModuleOp
if (spvMods.empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: drop {..} for trivial if statements per LLVM coding sytle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

llvm::SmallVector<uint32_t, 0> spvBinary;

spvBinary.clear();
// serialize the spv module to spv binary
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serialize the spv.module op to SPIR-V blob.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

spvBinary.clear();
// serialize the spv module to spv binary
if (mlir::failed(spirv::serialize(spvMod, spvBinary))) {
spvMod.emitError() << "Failed to serialize SPIR-V module";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "failed to .."

no capitalization to compose better with previous / following messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for the tip.

}
auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module);
auto spvMods = gpuMod.getOps<spirv::ModuleOp>();
// Empty spirv::ModuleOp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here does not provide additional value; we should remove it or expand it to be more clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@silee2
Copy link
Contributor Author

silee2 commented Oct 30, 2023

@antiagainst Thanks for the detailed review and helpful comments! Updated the PR accordingly.

@silee2
Copy link
Contributor Author

silee2 commented Nov 3, 2023

@antiagainst Waiting for your approval.

Copy link
Member

@antiagainst antiagainst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for addressing the comments!

@antiagainst antiagainst changed the title [MLIR] SPIRV Target Attribute [mlir][spirv] Implement gpu::TargetAttrInterface Nov 5, 2023
@antiagainst antiagainst merged commit 2dace04 into llvm:main Nov 5, 2023
@antiagainst
Copy link
Member

I revised the commit message a bit and landed it. Thanks for the waiting!

@JOE1994
Copy link
Member

JOE1994 commented Nov 5, 2023

This revision seems related to the following buildbot failure:

Would you mind taking a look? Thank you 👍

@antiagainst
Copy link
Member

Sorry about that! I uploaded 4a4b857 to fix this. Verified that it fixes the break for me locally.

@@ -15,6 +15,7 @@

#include "Utils.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels off: you have GPU dialect transforms depending on SPIRV attributes/dialect (esp in header). Why is this pass in GPU dialect rather than SPIRV one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Back when the compilation redesign was happening we decided to add the attach* passes in GPU to avoid polluting lower level dialects with GPU includes. However, I do agree that include shouldn't be there, as far as I could tell, that include is only needed by one pass option mlir::spirv::TargetEnvAttr::kUnknownDeviceID, so it should be possible to remove it. I'll fix it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SG. Thanks @jpienaar & @fabianmcg!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants