MLIR 24.0.0git
ROCDLAttachTarget.cpp
Go to the documentation of this file.
1//===- ROCDLAttachTarget.cpp - Attach an ROCDL target ---------------------===//
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 the `GpuROCDLAttachTarget` pass, attaching
10// `#rocdl.target` attributes to GPU modules.
11//
12//===----------------------------------------------------------------------===//
13
15
19#include "mlir/IR/Builders.h"
20#include "mlir/Pass/Pass.h"
22#include "llvm/Support/Regex.h"
23
24namespace mlir {
25#define GEN_PASS_DEF_GPUROCDLATTACHTARGET
26#include "mlir/Dialect/GPU/Transforms/Passes.h.inc"
27} // namespace mlir
28
29using namespace mlir;
30using namespace mlir::ROCDL;
31
32namespace {
33struct ROCDLAttachTarget
34 : public impl::GpuROCDLAttachTargetBase<ROCDLAttachTarget> {
35 using Base::Base;
36
37 DictionaryAttr getFlags(OpBuilder &builder, bool isWave64) const;
38
39 void runOnOperation() override;
40
41 void getDependentDialects(DialectRegistry &registry) const override {
42 registry.insert<ROCDL::ROCDLDialect>();
43 }
44};
45} // namespace
46
47DictionaryAttr ROCDLAttachTarget::getFlags(OpBuilder &builder,
48 bool isWave64) const {
49 UnitAttr unitAttr = builder.getUnitAttr();
50 SmallVector<NamedAttribute, 6> flags;
51 auto addFlag = [&](StringRef flag) {
52 flags.push_back(builder.getNamedAttr(flag, unitAttr));
53 };
54 if (!isWave64)
55 addFlag("no_wave64");
56 if (fastFlag)
57 addFlag("fast");
58 if (dazFlag)
59 addFlag("daz");
60 if (finiteOnlyFlag)
61 addFlag("finite_only");
62 if (unsafeMathFlag)
63 addFlag("unsafe_math");
64 if (!correctSqrtFlag)
65 addFlag("unsafe_sqrt");
66 if (!flags.empty())
67 return builder.getDictionaryAttr(flags);
68 return nullptr;
69}
70
71void ROCDLAttachTarget::runOnOperation() {
72 OpBuilder builder(&getContext());
73
74 // #rocdl.target feeds the TargetMachine, whose -mcpu is a bare processor
75 // name. Split an `arch` into the pieces the attribute wants, mirroring
76 // Clang.
77 std::string resolvedTriple = triple;
78 std::string resolvedChip = chip;
79 std::string resolvedFeatures = features;
80 // `wavesize` is the only wavefront-size control. Without an `arch` there is
81 // no target to ask, so leaving it at 0 keeps the Wave64 that `#rocdl.target`
82 // has always assumed.
83 bool resolvedWave64 = waveSize != 32;
84 // Set when `arch` was given and used so its xnack/sramecc modifiers can
85 // become module flags.
86 std::optional<ROCDL::TargetInfo> targetInfo;
87 if (!arch.empty()) {
88 std::optional<llvm::AMDGPU::TargetID> id =
90 if (!id) {
91 emitError(UnknownLoc::get(&getContext()))
92 << "'" << arch << "' is not a valid AMDGPU architecture";
93 return signalPassFailure();
94 }
95 // #rocdl.target requires a chip, so a triple that names no GPU (the legacy
96 // subarch-less "amdgcn-amd-amdhsa") cannot be attached.
97 if (id->getGPUKind() == llvm::AMDGPU::GK_NONE) {
98 emitError(UnknownLoc::get(&getContext()))
99 << "'" << arch
100 << "' names no GPU; a chip is required to attach a "
101 "target";
102 return signalPassFailure();
103 }
104
105 llvm::Triple parsed(id->getTargetTripleString());
106
107 StringRef archName = parsed.getArchName();
108 llvm::Triple::SubArchType subArch =
109 llvm::AMDGPU::getSubArch(id->getGPUKind());
110 if (StringRef subArchName = llvm::AMDGPU::getSubArchName(subArch);
111 !subArchName.empty())
112 archName = subArchName;
113
114 // Drop the "unknown" environment part of triples since a lot of the
115 // toolchain expects a 3-component form.
116 resolvedTriple =
117 (parsed.getEnvironment() == llvm::Triple::UnknownEnvironment
118 ? llvm::Triple(archName, parsed.getVendorName(),
119 parsed.getOSName())
120 : llvm::Triple(archName, parsed.getVendorName(),
121 parsed.getOSName(), parsed.getEnvironmentName()))
122 .str();
123 resolvedChip = llvm::AMDGPU::getArchNameAMDGCN(id->getGPUKind()).str();
124
125 // Take the wavefront size from the target, since `wavesize`'s Wave64
126 // fallback is wrong on targets like gfx10.
127 FailureOr<ROCDL::TargetInfo> info =
128 ROCDL::TargetInfo::get(arch, waveSize, [&] {
129 return emitError(UnknownLoc::get(&getContext()));
130 });
131 if (failed(info))
132 return signalPassFailure();
133 targetInfo = *info;
134 resolvedWave64 = info->getWavefrontSize() == 64;
135
136 // Record the wavefrontsize option into the features set so that the device
137 // libraries and codegen agree with each other in cases where both
138 // wavefontsize32 and wavefrontsize64 are permitted options.
139 if (info->supportsBothWavefrontSizes()) {
140 if (!resolvedFeatures.empty())
141 resolvedFeatures += ",";
142 resolvedFeatures +=
143 resolvedWave64 ? "+wavefrontsize64" : "+wavefrontsize32";
144 }
145 } else if (waveSize != 0 && waveSize != 32 && waveSize != 64) {
146 emitError(UnknownLoc::get(&getContext()))
147 << "wavefront size must be 32 or 64, got " << waveSize;
148 return signalPassFailure();
149 }
150
151 ArrayRef<std::string> libs(linkLibs);
152 SmallVector<StringRef> filesToLink(libs);
153 auto target = builder.getAttr<ROCDLTargetAttr>(
154 optLevel, resolvedTriple, resolvedChip, resolvedFeatures, abiVersion,
155 getFlags(builder, resolvedWave64),
156 filesToLink.empty() ? nullptr : builder.getStrArrayAttr(filesToLink));
157 llvm::Regex matcher(moduleMatcher);
158 for (Region &region : getOperation()->getRegions())
159 for (Block &block : region.getBlocks())
160 for (auto module : block.getOps<gpu::GPUModuleOp>()) {
161 // Check if the name of the module matches.
162 if (!moduleMatcher.empty() && !matcher.match(module.getName()))
163 continue;
164 // Create the target array.
165 SmallVector<Attribute> targets;
166 if (std::optional<ArrayAttr> attrs = module.getTargets())
167 targets.append(attrs->getValue().begin(), attrs->getValue().end());
168 targets.push_back(target);
169 // Remove any duplicate targets.
170 targets.erase(llvm::unique(targets), targets.end());
171 // Update the target attribute array.
172 module.setTargetsAttr(builder.getArrayAttr(targets));
173 if (targetInfo)
174 targetInfo->migrateArchFeaturesToModuleFlags(module);
175 }
176}
b getContext())
UnitAttr getUnitAttr()
Definition Builders.cpp:106
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
Definition Builders.cpp:112
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition Builders.cpp:102
ArrayAttr getStrArrayAttr(ArrayRef< StringRef > values)
Definition Builders.cpp:315
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
Definition Builders.h:101
This class helps build Operations.
Definition Builders.h:210
static FailureOr< TargetInfo > get(StringRef arch, unsigned waveSize=0, function_ref< InFlightDiagnostic()> emitError=nullptr)
Resolves a target description.
static std::optional<::llvm::AMDGPU::TargetID > parseTargetID(StringRef arch)
Parses arch into a target ID, accepting the spellings get() documents, or returns nullopt if it names...
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:734
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.