clang 24.0.0git
LowerToLLVMIR.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 lowering of CIR attributes and operations directly to
10// LLVMIR.
11//
12//===----------------------------------------------------------------------===//
13
14#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15#include "mlir/IR/DialectRegistry.h"
16#include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
17#include "mlir/Target/LLVMIR/ModuleTranslation.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/IR/Constant.h"
21#include "llvm/IR/Constants.h"
22#include "llvm/IR/GlobalVariable.h"
23#include "llvm/IR/MDBuilder.h"
24#include "llvm/IR/Metadata.h"
25#include "llvm/Support/AMDGPUAddrSpace.h"
26
27using namespace llvm;
28
29namespace cir {
30namespace direct {
31
32/// Implementation of the dialect interface that converts CIR attributes to LLVM
33/// IR metadata.
35 : public mlir::LLVMTranslationDialectInterface {
36public:
37 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
38
39 /// Translates the given operation to LLVM IR using the provided IR builder
40 /// and saving the state in `moduleTranslation`.
41 mlir::LogicalResult convertOperation(
42 mlir::Operation *op, llvm::IRBuilderBase &builder,
43 mlir::LLVM::ModuleTranslation &moduleTranslation) const final {
44
45 if (auto cirOp = llvm::dyn_cast<mlir::LLVM::ZeroOp>(op))
46 moduleTranslation.mapValue(cirOp.getResult()) =
47 llvm::Constant::getNullValue(
48 moduleTranslation.convertType(cirOp.getType()));
49
50 return mlir::success();
51 }
52
53 /// Any named attribute in the CIR dialect, i.e, with name started with
54 /// "cir.", will be handled here.
55 virtual mlir::LogicalResult amendOperation(
56 mlir::Operation *op, llvm::ArrayRef<llvm::Instruction *> instructions,
57 mlir::NamedAttribute attribute,
58 mlir::LLVM::ModuleTranslation &moduleTranslation) const override {
59 if (auto func = dyn_cast<mlir::LLVM::LLVMFuncOp>(op)) {
60 if (mlir::failed(
61 amendFunction(func, instructions, attribute, moduleTranslation)))
62 return mlir::failure();
63 } else if (auto mod = dyn_cast<mlir::ModuleOp>(op)) {
64 if (mlir::failed(amendModule(mod, attribute, moduleTranslation)))
65 return mlir::failure();
66 } else if (attribute.getName() == "cir.riscv_nontemporal_domain") {
67 if (mlir::failed(amendRISCVNontemporalDomain(op, instructions, attribute,
68 moduleTranslation)))
69 return mlir::failure();
70 } else if (attribute.getName() == cir::CIRDialect::getSrcLocAttrName()) {
71 if (mlir::failed(amendSrcLoc(instructions, attribute, moduleTranslation)))
72 return mlir::failure();
73 } else if (attribute.getName() ==
74 cir::CIRDialect::getAMDGPUNoFineGrainedMemoryAttrName() ||
75 attribute.getName() ==
76 cir::CIRDialect::getAMDGPUNoRemoteMemoryAttrName() ||
77 attribute.getName() ==
78 cir::CIRDialect::getAMDGPUIgnoreDenormalModeAttrName() ||
79 attribute.getName() ==
80 cir::CIRDialect::getAMDGPUNoPrivateAddrSpaceAttrName()) {
81 amendAMDGPUAtomicMetadata(instructions, attribute, moduleTranslation);
82 }
83 return mlir::success();
84 }
85
86private:
87 // Convert the raw-encoded clang::SourceLocation into !srcloc, so that
88 // dontcall-error/warn works.
89 mlir::LogicalResult
90 amendSrcLoc(llvm::ArrayRef<llvm::Instruction *> instructions,
91 mlir::NamedAttribute attribute,
92 mlir::LLVM::ModuleTranslation &moduleTranslation) const {
93 auto srcLoc = mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue());
94 if (!srcLoc)
95 return mlir::failure();
96
97 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
98 llvm::MDNode *node = llvm::MDNode::get(
99 llvmContext, llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
100 llvm::Type::getInt64Ty(llvmContext),
101 srcLoc.getValue().getZExtValue())));
102 for (llvm::Instruction *inst : instructions)
103 inst->setMetadata("srcloc", node);
104 return mlir::success();
105 }
106
107 /// Attach the AMDGPU atomic metadata that lets the backend select a native
108 /// atomic instruction instead of expanding to a cmpxchg loop.
109 void amendAMDGPUAtomicMetadata(
111 mlir::NamedAttribute attribute,
112 mlir::LLVM::ModuleTranslation &moduleTranslation) const {
113 if (attribute.getName() ==
114 cir::CIRDialect::getAMDGPUNoPrivateAddrSpaceAttrName()) {
115 llvm::MDBuilder mdHelper(moduleTranslation.getLLVMContext());
116 llvm::MDNode *asRange = mdHelper.createRange(
117 llvm::APInt(32, llvm::AMDGPUAS::PRIVATE_ADDRESS),
118 llvm::APInt(32, llvm::AMDGPUAS::PRIVATE_ADDRESS + 1));
119 for (llvm::Instruction *inst : instructions)
120 inst->setMetadata(llvm::LLVMContext::MD_noalias_addrspace, asRange);
121 return;
122 }
123 llvm::MDNode *empty =
124 llvm::MDNode::get(moduleTranslation.getLLVMContext(), {});
125 // !atomic.ignore.denormal.mode is a fixed metadata kind so it has to be
126 // attached via its enum rather than by name.
127 if (attribute.getName() ==
128 cir::CIRDialect::getAMDGPUIgnoreDenormalModeAttrName()) {
129 for (llvm::Instruction *inst : instructions)
130 inst->setMetadata(llvm::LLVMContext::MD_atomic_ignore_denormal_mode,
131 empty);
132 return;
133 }
134 llvm::StringRef mdName;
135 if (attribute.getName() ==
136 cir::CIRDialect::getAMDGPUNoFineGrainedMemoryAttrName())
137 mdName = "amdgpu.no.fine.grained.memory";
138 else if (attribute.getName() ==
139 cir::CIRDialect::getAMDGPUNoRemoteMemoryAttrName())
140 mdName = "amdgpu.no.remote.memory";
141 for (llvm::Instruction *inst : instructions)
142 inst->setMetadata(mdName, empty);
143 }
144
145 mlir::LogicalResult amendRISCVNontemporalDomain(
146 mlir::Operation *op, llvm::ArrayRef<llvm::Instruction *> instructions,
147 mlir::NamedAttribute attribute,
148 mlir::LLVM::ModuleTranslation &moduleTranslation) const {
149 auto domain = mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue());
150 if (!domain)
151 return op->emitError()
152 << "expected cir.riscv_nontemporal_domain to be an integer";
153
154 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
155 llvm::MDNode *node = llvm::MDNode::get(
156 llvmContext, llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
157 llvm::Type::getInt32Ty(llvmContext),
158 domain.getValue().getZExtValue())));
159 for (llvm::Instruction *inst : instructions)
160 inst->setMetadata("riscv-nontemporal-domain", node);
161 return mlir::success();
162 }
163
164 // Translate CIR function attributes to LLVM function attributes.
165 mlir::LogicalResult
166 amendFunction(mlir::LLVM::LLVMFuncOp func,
167 llvm::ArrayRef<llvm::Instruction *> instructions,
168 mlir::NamedAttribute attribute,
169 mlir::LLVM::ModuleTranslation &moduleTranslation) const {
170 llvm::Function *llvmFunc = moduleTranslation.lookupFunction(func.getName());
171 llvm::StringRef attrName = attribute.getName().strref();
172
173 // Strip the "cir." prefix to get the LLVM attribute name.
174 llvm::StringRef llvmAttrName = attrName.substr(strlen("cir."));
175 if (auto strAttr = mlir::dyn_cast<mlir::StringAttr>(attribute.getValue()))
176 llvmFunc->addFnAttr(llvmAttrName, strAttr.getValue());
177 return mlir::success();
178 }
179
180 // Translate CIR's module attributes to LLVM's module metadata
181 mlir::LogicalResult
182 amendModule(mlir::ModuleOp mod, mlir::NamedAttribute attribute,
183 mlir::LLVM::ModuleTranslation &moduleTranslation) const {
184 llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
185 llvm::LLVMContext &llvmContext = llvmModule->getContext();
186
187 if (attribute.getName() == "cir.amdhsa_code_object_version") {
188 if (auto intAttr =
189 mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue())) {
190 llvmModule->addModuleFlag(llvm::Module::Error,
191 "amdhsa_code_object_version",
192 static_cast<uint32_t>(intAttr.getInt()));
193 }
194 }
195
196 if (attribute.getName() == "cir.amdgpu_printf_kind") {
197 if (auto strAttr =
198 mlir::dyn_cast<mlir::StringAttr>(attribute.getValue())) {
199 llvm::MDString *mdStr =
200 llvm::MDString::get(llvmContext, strAttr.getValue());
201 llvmModule->addModuleFlag(llvm::Module::Error, "amdgpu_printf_kind",
202 mdStr);
203 }
204 }
205
206 if (attribute.getName() == "cir.amdgpu_xnack") {
207 if (auto intAttr =
208 mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue())) {
209 llvmModule->addModuleFlag(llvm::Module::Error, "amdgpu.xnack",
210 static_cast<uint32_t>(intAttr.getInt()));
211 }
212 }
213
214 if (attribute.getName() == "cir.amdgpu_sramecc") {
215 if (auto intAttr =
216 mlir::dyn_cast<mlir::IntegerAttr>(attribute.getValue())) {
217 llvmModule->addModuleFlag(llvm::Module::Error, "amdgpu.sramecc",
218 static_cast<uint32_t>(intAttr.getInt()));
219 }
220 }
221
222 return mlir::success();
223 }
224};
225
226void registerCIRDialectTranslation(mlir::DialectRegistry &registry) {
227 registry.insert<cir::CIRDialect>();
228 registry.addExtension(+[](mlir::MLIRContext *ctx, cir::CIRDialect *dialect) {
229 dialect->addInterfaces<CIRDialectLLVMIRTranslationInterface>();
230 });
231}
232
233} // namespace direct
234} // namespace cir
235
236namespace mlir {
237void registerCIRDialectTranslation(mlir::MLIRContext &context) {
238 mlir::DialectRegistry registry;
240 context.appendDialectRegistry(registry);
241}
242} // namespace mlir
Implementation of the dialect interface that converts CIR attributes to LLVM IR metadata.
mlir::LogicalResult convertOperation(mlir::Operation *op, llvm::IRBuilderBase &builder, mlir::LLVM::ModuleTranslation &moduleTranslation) const final
Translates the given operation to LLVM IR using the provided IR builder and saving the state in modul...
virtual mlir::LogicalResult amendOperation(mlir::Operation *op, llvm::ArrayRef< llvm::Instruction * > instructions, mlir::NamedAttribute attribute, mlir::LLVM::ModuleTranslation &moduleTranslation) const override
Any named attribute in the CIR dialect, i.e, with name started with "cir.", will be handled here.
void registerCIRDialectTranslation(mlir::DialectRegistry &registry)
RangeSelector node(std::string ID)
Selects a node, including trailing semicolon, if any (for declarations and non-expression statements)...
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
void registerCIRDialectTranslation(mlir::MLIRContext &context)