MLIR 23.0.0git
ModuleTranslation.cpp
Go to the documentation of this file.
1//===- ModuleTranslation.cpp - MLIR to LLVM conversion --------------------===//
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 translation between an MLIR LLVM dialect module and
10// the corresponding LLVMIR module. It only handles core LLVM IR operations.
11//
12//===----------------------------------------------------------------------===//
13
15
16#include "AttrKindDetail.h"
17#include "DebugTranslation.h"
26#include "mlir/IR/Attributes.h"
27#include "mlir/IR/BuiltinOps.h"
30#include "mlir/Support/LLVM.h"
33
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/StringExtras.h"
36#include "llvm/ADT/TypeSwitch.h"
37#include "llvm/Analysis/TargetFolder.h"
38#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
39#include "llvm/IR/BasicBlock.h"
40#include "llvm/IR/CFG.h"
41#include "llvm/IR/Constants.h"
42#include "llvm/IR/DerivedTypes.h"
43#include "llvm/IR/IRBuilder.h"
44#include "llvm/IR/InlineAsm.h"
45#include "llvm/IR/LLVMContext.h"
46#include "llvm/IR/MDBuilder.h"
47#include "llvm/IR/Module.h"
48#include "llvm/IR/Verifier.h"
49#include "llvm/Support/Debug.h"
50#include "llvm/Support/ErrorHandling.h"
51#include "llvm/Support/VirtualFileSystem.h"
52#include "llvm/Support/raw_ostream.h"
53#include "llvm/Transforms/Utils/BasicBlockUtils.h"
54#include "llvm/Transforms/Utils/Cloning.h"
55#include "llvm/Transforms/Utils/ModuleUtils.h"
56#include <numeric>
57#include <optional>
58
59#define DEBUG_TYPE "llvm-dialect-to-llvm-ir"
60
61using namespace mlir;
62using namespace mlir::LLVM;
63using namespace mlir::LLVM::detail;
64
65#include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
66
67namespace {
68/// A customized inserter for LLVM's IRBuilder that captures all LLVM IR
69/// instructions that are created for future reference.
70///
71/// This is intended to be used with the `CollectionScope` RAII object:
72///
73/// llvm::IRBuilder<..., InstructionCapturingInserter> builder;
74/// {
75/// InstructionCapturingInserter::CollectionScope scope(builder);
76/// // Call IRBuilder methods as usual.
77///
78/// // This will return a list of all instructions created by the builder,
79/// // in order of creation.
80/// builder.getInserter().getCapturedInstructions();
81/// }
82/// // This will return an empty list.
83/// builder.getInserter().getCapturedInstructions();
84///
85/// The capturing functionality is _disabled_ by default for performance
86/// consideration. It needs to be explicitly enabled, which is achieved by
87/// creating a `CollectionScope`.
88class InstructionCapturingInserter : public llvm::IRBuilderCallbackInserter {
89public:
90 /// Constructs the inserter.
91 InstructionCapturingInserter()
92 : llvm::IRBuilderCallbackInserter([this](llvm::Instruction *instruction) {
93 if (LLVM_LIKELY(enabled))
94 capturedInstructions.push_back(instruction);
95 }) {}
96
97 /// Returns the list of LLVM IR instructions captured since the last cleanup.
98 ArrayRef<llvm::Instruction *> getCapturedInstructions() const {
99 return capturedInstructions;
100 }
101
102 /// Clears the list of captured LLVM IR instructions.
103 void clearCapturedInstructions() { capturedInstructions.clear(); }
104
105 /// RAII object enabling the capture of created LLVM IR instructions.
106 class CollectionScope {
107 public:
108 /// Creates the scope for the given inserter.
109 CollectionScope(llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing);
110
111 /// Ends the scope.
112 ~CollectionScope();
113
114 ArrayRef<llvm::Instruction *> getCapturedInstructions() {
115 if (!inserter)
116 return {};
117 return inserter->getCapturedInstructions();
118 }
119
120 private:
121 /// Back reference to the inserter.
122 InstructionCapturingInserter *inserter = nullptr;
123
124 /// List of instructions in the inserter prior to this scope.
125 SmallVector<llvm::Instruction *> previouslyCollectedInstructions;
126
127 /// Whether the inserter was enabled prior to this scope.
128 bool wasEnabled;
129 };
130
131 /// Enable or disable the capturing mechanism.
132 void setEnabled(bool enabled = true) { this->enabled = enabled; }
133
134private:
135 /// List of captured instructions.
136 SmallVector<llvm::Instruction *> capturedInstructions;
137
138 /// Whether the collection is enabled.
139 bool enabled = false;
140};
141
142using CapturingIRBuilder =
143 llvm::IRBuilder<llvm::TargetFolder, InstructionCapturingInserter>;
144} // namespace
145
146InstructionCapturingInserter::CollectionScope::CollectionScope(
147 llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing) {
148
149 if (!isBuilderCapturing)
150 return;
151
152 auto &capturingIRBuilder = static_cast<CapturingIRBuilder &>(irBuilder);
153 inserter = &capturingIRBuilder.getInserter();
154 wasEnabled = inserter->enabled;
155 if (wasEnabled)
156 previouslyCollectedInstructions.swap(inserter->capturedInstructions);
157 inserter->setEnabled(true);
158}
159
160InstructionCapturingInserter::CollectionScope::~CollectionScope() {
161 if (!inserter)
162 return;
163
164 previouslyCollectedInstructions.swap(inserter->capturedInstructions);
165 // If collection was enabled (likely in another, surrounding scope), keep
166 // the instructions collected in this scope.
167 if (wasEnabled) {
168 llvm::append_range(inserter->capturedInstructions,
169 previouslyCollectedInstructions);
170 }
171 inserter->setEnabled(wasEnabled);
172}
173
174/// Translates the given data layout spec attribute to the LLVM IR data layout.
175/// Only integer, float, pointer and endianness entries are currently supported.
176static FailureOr<llvm::DataLayout>
177translateDataLayout(DataLayoutSpecInterface attribute,
178 const DataLayout &dataLayout,
179 std::optional<Location> loc = std::nullopt) {
180 if (!loc)
181 loc = UnknownLoc::get(attribute.getContext());
182
183 // Translate the endianness attribute.
184 std::string llvmDataLayout;
185 llvm::raw_string_ostream layoutStream(llvmDataLayout);
186 for (DataLayoutEntryInterface entry : attribute.getEntries()) {
187 auto key = llvm::dyn_cast_if_present<StringAttr>(entry.getKey());
188 if (!key)
189 continue;
190 if (key.getValue() == DLTIDialect::kDataLayoutEndiannessKey) {
191 auto value = cast<StringAttr>(entry.getValue());
192 bool isLittleEndian =
193 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle;
194 layoutStream << "-" << (isLittleEndian ? "e" : "E");
195 continue;
196 }
197 if (key.getValue() == DLTIDialect::kDataLayoutManglingModeKey) {
198 auto value = cast<StringAttr>(entry.getValue());
199 layoutStream << "-m:" << value.getValue();
200 continue;
201 }
202 if (key.getValue() == DLTIDialect::kDataLayoutProgramMemorySpaceKey) {
203 auto value = cast<IntegerAttr>(entry.getValue());
204 uint64_t space = value.getValue().getZExtValue();
205 // Skip the default address space.
206 if (space == 0)
207 continue;
208 layoutStream << "-P" << space;
209 continue;
210 }
211 if (key.getValue() == DLTIDialect::kDataLayoutGlobalMemorySpaceKey) {
212 auto value = cast<IntegerAttr>(entry.getValue());
213 uint64_t space = value.getValue().getZExtValue();
214 // Skip the default address space.
215 if (space == 0)
216 continue;
217 layoutStream << "-G" << space;
218 continue;
219 }
220 if (key.getValue() == DLTIDialect::kDataLayoutAllocaMemorySpaceKey) {
221 auto value = cast<IntegerAttr>(entry.getValue());
222 uint64_t space = value.getValue().getZExtValue();
223 // Skip the default address space.
224 if (space == 0)
225 continue;
226 layoutStream << "-A" << space;
227 continue;
228 }
229 if (key.getValue() == DLTIDialect::kDataLayoutStackAlignmentKey) {
230 auto value = cast<IntegerAttr>(entry.getValue());
231 uint64_t alignment = value.getValue().getZExtValue();
232 // Skip the default stack alignment.
233 if (alignment == 0)
234 continue;
235 layoutStream << "-S" << alignment;
236 continue;
237 }
238 if (key.getValue() == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey) {
239 auto value = cast<FunctionPointerAlignmentAttr>(entry.getValue());
240 uint64_t alignment = value.getAlignment();
241 // Skip the default function pointer alignment.
242 if (alignment == 0)
243 continue;
244 layoutStream << "-F" << (value.getFunctionDependent() ? "n" : "i")
245 << alignment;
246 continue;
247 }
248 if (key.getValue() == DLTIDialect::kDataLayoutLegalIntWidthsKey) {
249 layoutStream << "-n";
250 llvm::interleave(
251 cast<DenseI32ArrayAttr>(entry.getValue()).asArrayRef(), layoutStream,
252 [&](int32_t val) { layoutStream << val; }, ":");
253 continue;
254 }
255 emitError(*loc) << "unsupported data layout key " << key;
256 return failure();
257 }
258
259 // Go through the list of entries to check which types are explicitly
260 // specified in entries. Where possible, data layout queries are used instead
261 // of directly inspecting the entries.
262 for (DataLayoutEntryInterface entry : attribute.getEntries()) {
263 auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
264 if (!type)
265 continue;
266 // Data layout for the index type is irrelevant at this point.
267 if (isa<IndexType>(type))
268 continue;
269 layoutStream << "-";
270 LogicalResult result =
272 .Case<IntegerType, Float16Type, Float32Type, Float64Type,
273 Float80Type, Float128Type>([&](Type type) -> LogicalResult {
274 if (auto intType = dyn_cast<IntegerType>(type)) {
275 if (intType.getSignedness() != IntegerType::Signless)
276 return emitError(*loc)
277 << "unsupported data layout for non-signless integer "
278 << intType;
279 layoutStream << "i";
280 } else {
281 layoutStream << "f";
282 }
283 uint64_t size = dataLayout.getTypeSizeInBits(type);
284 uint64_t abi = dataLayout.getTypeABIAlignment(type) * 8u;
285 uint64_t preferred =
286 dataLayout.getTypePreferredAlignment(type) * 8u;
287 layoutStream << size << ":" << abi;
288 if (abi != preferred)
289 layoutStream << ":" << preferred;
290 return success();
291 })
292 .Case([&](LLVMPointerType type) {
293 layoutStream << "p" << type.getAddressSpace() << ":";
294 uint64_t size = dataLayout.getTypeSizeInBits(type);
295 uint64_t abi = dataLayout.getTypeABIAlignment(type) * 8u;
296 uint64_t preferred =
297 dataLayout.getTypePreferredAlignment(type) * 8u;
298 uint64_t index = *dataLayout.getTypeIndexBitwidth(type);
299 layoutStream << size << ":" << abi << ":" << preferred << ":"
300 << index;
301 return success();
302 })
303 .Default([loc](Type type) {
304 return emitError(*loc)
305 << "unsupported type in data layout: " << type;
306 });
307 if (failed(result))
308 return failure();
309 }
310 StringRef layoutSpec(llvmDataLayout);
311 layoutSpec.consume_front("-");
312
313 return llvm::DataLayout(layoutSpec);
314}
315
316/// Builds a constant of a sequential LLVM type `type`, potentially containing
317/// other sequential types recursively, from the individual constant values
318/// provided in `constants`. `shape` contains the number of elements in nested
319/// sequential types. Reports errors at `loc` and returns nullptr on error.
320static llvm::Constant *
322 ArrayRef<int64_t> shape, llvm::Type *type,
323 Location loc) {
324 if (shape.empty()) {
325 llvm::Constant *result = constants.front();
326 constants = constants.drop_front();
327 return result;
328 }
329
330 llvm::Type *elementType;
331 if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
332 elementType = arrayTy->getElementType();
333 } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
334 elementType = vectorTy->getElementType();
335 } else {
336 emitError(loc) << "expected sequential LLVM types wrapping a scalar";
337 return nullptr;
338 }
339
341 nested.reserve(shape.front());
342 for (int64_t i = 0; i < shape.front(); ++i) {
343 nested.push_back(buildSequentialConstant(constants, shape.drop_front(),
344 elementType, loc));
345 if (!nested.back())
346 return nullptr;
347 }
348
349 if (shape.size() == 1 && type->isVectorTy())
350 return llvm::ConstantVector::get(nested);
351 return llvm::ConstantArray::get(
352 llvm::ArrayType::get(elementType, shape.front()), nested);
353}
354
355/// Returns the first non-sequential type nested in sequential types.
356static llvm::Type *getInnermostElementType(llvm::Type *type) {
357 do {
358 if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
359 type = arrayTy->getElementType();
360 } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
361 type = vectorTy->getElementType();
362 } else {
363 return type;
364 }
365 } while (true);
366}
367
368/// Convert a dense elements attribute to an LLVM IR constant using its raw data
369/// storage if possible. This supports elements attributes of tensor or vector
370/// type and avoids constructing separate objects for individual values of the
371/// innermost dimension. Constants for other dimensions are still constructed
372/// recursively. Returns null if constructing from raw data is not supported for
373/// this type, e.g., element type is not a power-of-two-sized primitive. Reports
374/// other errors at `loc`.
375static llvm::Constant *
377 llvm::Type *llvmType,
378 const ModuleTranslation &moduleTranslation) {
379 if (!denseElementsAttr)
380 return nullptr;
381
382 llvm::Type *innermostLLVMType = getInnermostElementType(llvmType);
383 if (!llvm::ConstantDataSequential::isElementTypeCompatible(innermostLLVMType))
384 return nullptr;
385
386 ShapedType type = denseElementsAttr.getType();
387 if (type.getNumElements() == 0)
388 return nullptr;
389
390 // Check that the raw data size matches what is expected for the scalar size.
391 // TODO: in theory, we could repack the data here to keep constructing from
392 // raw data.
393 // TODO: we may also need to consider endianness when cross-compiling to an
394 // architecture where it is different.
395 int64_t elementByteSize = denseElementsAttr.getRawData().size() /
396 denseElementsAttr.getNumElements();
397 if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits())
398 return nullptr;
399
400 // Compute the shape of all dimensions but the innermost. Note that the
401 // innermost dimension may be that of the vector element type.
402 bool hasVectorElementType = isa<VectorType>(type.getElementType());
403 int64_t numAggregates =
404 denseElementsAttr.getNumElements() /
405 (hasVectorElementType ? 1
406 : denseElementsAttr.getType().getShape().back());
407 ArrayRef<int64_t> outerShape = type.getShape();
408 if (!hasVectorElementType)
409 outerShape = outerShape.drop_back();
410
411 // Handle the case of vector splat, LLVM has special support for it.
412 if (denseElementsAttr.isSplat() &&
413 (isa<VectorType>(type) || hasVectorElementType)) {
414 llvm::Constant *splatValue = LLVM::detail::getLLVMConstant(
415 innermostLLVMType, denseElementsAttr.getSplatValue<Attribute>(), loc,
416 moduleTranslation);
417 llvm::Constant *splatVector =
418 llvm::ConstantDataVector::getSplat(0, splatValue);
419 SmallVector<llvm::Constant *> constants(numAggregates, splatVector);
420 ArrayRef<llvm::Constant *> constantsRef = constants;
421 return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
422 }
423 if (denseElementsAttr.isSplat())
424 return nullptr;
425
426 // In case of non-splat, create a constructor for the innermost constant from
427 // a piece of raw data.
428 std::function<llvm::Constant *(StringRef)> buildCstData;
429 if (isa<TensorType>(type)) {
430 auto vectorElementType = dyn_cast<VectorType>(type.getElementType());
431 if (vectorElementType && vectorElementType.getRank() == 1) {
432 buildCstData = [&](StringRef data) {
433 return llvm::ConstantDataVector::getRaw(
434 data, vectorElementType.getShape().back(), innermostLLVMType);
435 };
436 } else if (!vectorElementType) {
437 buildCstData = [&](StringRef data) {
438 return llvm::ConstantDataArray::getRaw(data, type.getShape().back(),
439 innermostLLVMType);
440 };
441 }
442 } else if (isa<VectorType>(type)) {
443 buildCstData = [&](StringRef data) {
444 return llvm::ConstantDataVector::getRaw(data, type.getShape().back(),
445 innermostLLVMType);
446 };
447 }
448 if (!buildCstData)
449 return nullptr;
450
451 // Create innermost constants and defer to the default constant creation
452 // mechanism for other dimensions.
454 int64_t aggregateSize = denseElementsAttr.getType().getShape().back() *
455 (innermostLLVMType->getScalarSizeInBits() / 8);
456 constants.reserve(numAggregates);
457 for (unsigned i = 0; i < numAggregates; ++i) {
458 StringRef data(denseElementsAttr.getRawData().data() + i * aggregateSize,
459 aggregateSize);
460 constants.push_back(buildCstData(data));
461 }
462
463 ArrayRef<llvm::Constant *> constantsRef = constants;
464 return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
465}
466
467/// Convert a dense resource elements attribute to an LLVM IR constant using its
468/// raw data storage if possible. This supports elements attributes of tensor or
469/// vector type and avoids constructing separate objects for individual values
470/// of the innermost dimension. Constants for other dimensions are still
471/// constructed recursively. Returns nullptr on failure and emits errors at
472/// `loc`.
473static llvm::Constant *convertDenseResourceElementsAttr(
474 Location loc, DenseResourceElementsAttr denseResourceAttr,
475 llvm::Type *llvmType, const ModuleTranslation &moduleTranslation) {
476 assert(denseResourceAttr && "expected non-null attribute");
477
478 llvm::Type *innermostLLVMType = getInnermostElementType(llvmType);
479 if (!llvm::ConstantDataSequential::isElementTypeCompatible(
480 innermostLLVMType)) {
481 emitError(loc, "no known conversion for innermost element type");
482 return nullptr;
483 }
484
485 ShapedType type = denseResourceAttr.getType();
486 assert(type.getNumElements() > 0 && "Expected non-empty elements attribute");
487
488 AsmResourceBlob *blob = denseResourceAttr.getRawHandle().getBlob();
489 if (!blob) {
490 emitError(loc, "resource does not exist");
491 return nullptr;
492 }
493
494 ArrayRef<char> rawData = blob->getData();
495
496 // Check that the raw data size matches what is expected for the scalar size.
497 // TODO: in theory, we could repack the data here to keep constructing from
498 // raw data.
499 // TODO: we may also need to consider endianness when cross-compiling to an
500 // architecture where it is different.
501 int64_t numElements = denseResourceAttr.getType().getNumElements();
502 int64_t elementByteSize = rawData.size() / numElements;
503 if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits()) {
504 emitError(loc, "raw data size does not match element type size");
505 return nullptr;
506 }
507
508 // Compute the shape of all dimensions but the innermost. Note that the
509 // innermost dimension may be that of the vector element type.
510 bool hasVectorElementType = isa<VectorType>(type.getElementType());
511 int64_t numAggregates =
512 numElements / (hasVectorElementType
513 ? 1
514 : denseResourceAttr.getType().getShape().back());
515 ArrayRef<int64_t> outerShape = type.getShape();
516 if (!hasVectorElementType)
517 outerShape = outerShape.drop_back();
518
519 // Create a constructor for the innermost constant from a piece of raw data.
520 std::function<llvm::Constant *(StringRef)> buildCstData;
521 if (isa<TensorType>(type)) {
522 auto vectorElementType = dyn_cast<VectorType>(type.getElementType());
523 if (vectorElementType && vectorElementType.getRank() == 1) {
524 buildCstData = [&](StringRef data) {
525 return llvm::ConstantDataVector::getRaw(
526 data, vectorElementType.getShape().back(), innermostLLVMType);
527 };
528 } else if (!vectorElementType) {
529 buildCstData = [&](StringRef data) {
530 return llvm::ConstantDataArray::getRaw(data, type.getShape().back(),
531 innermostLLVMType);
532 };
533 }
534 } else if (isa<VectorType>(type)) {
535 buildCstData = [&](StringRef data) {
536 return llvm::ConstantDataVector::getRaw(data, type.getShape().back(),
537 innermostLLVMType);
538 };
539 }
540 if (!buildCstData) {
541 emitError(loc, "unsupported dense_resource type");
542 return nullptr;
543 }
544
545 // Create innermost constants and defer to the default constant creation
546 // mechanism for other dimensions.
548 int64_t aggregateSize = denseResourceAttr.getType().getShape().back() *
549 (innermostLLVMType->getScalarSizeInBits() / 8);
550 constants.reserve(numAggregates);
551 for (unsigned i = 0; i < numAggregates; ++i) {
552 StringRef data(rawData.data() + i * aggregateSize, aggregateSize);
553 constants.push_back(buildCstData(data));
554 }
555
556 ArrayRef<llvm::Constant *> constantsRef = constants;
557 return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
558}
559
560/// Create an LLVM IR constant of `llvmType` from the MLIR attribute `attr`.
561/// This currently supports integer, floating point, splat and dense element
562/// attributes and combinations thereof. Also, an array attribute with two
563/// elements is supported to represent a complex constant. In case of error,
564/// report it to `loc` and return nullptr.
566 llvm::Type *llvmType, Attribute attr, Location loc,
567 const ModuleTranslation &moduleTranslation) {
568 if (!attr || isa<UndefAttr>(attr))
569 return llvm::UndefValue::get(llvmType);
570 if (isa<ZeroAttr>(attr))
571 return llvm::Constant::getNullValue(llvmType);
572 if (auto *structType = dyn_cast<::llvm::StructType>(llvmType)) {
573 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
574 if (!arrayAttr) {
575 emitError(loc, "expected an array attribute for a struct constant");
576 return nullptr;
577 }
578 SmallVector<llvm::Constant *> structElements;
579 structElements.reserve(structType->getNumElements());
580 for (auto [elemType, elemAttr] :
581 zip_equal(structType->elements(), arrayAttr)) {
582 llvm::Constant *element =
583 getLLVMConstant(elemType, elemAttr, loc, moduleTranslation);
584 if (!element)
585 return nullptr;
586 structElements.push_back(element);
587 }
588 return llvm::ConstantStruct::get(structType, structElements);
589 }
590 // For integer types, we allow a mismatch in sizes as the index type in
591 // MLIR might have a different size than the index type in the LLVM module.
592 if (auto intAttr = dyn_cast<IntegerAttr>(attr)) {
593 // If the attribute is an unsigned integer or a 1-bit integer, zero-extend
594 // the value to the bit width of the LLVM type. Otherwise, sign-extend.
595 auto intTy = dyn_cast<IntegerType>(intAttr.getType());
596 APInt value;
597 if (intTy && (intTy.isUnsigned() || intTy.getWidth() == 1))
598 value = intAttr.getValue().zextOrTrunc(llvmType->getIntegerBitWidth());
599 else
600 value = intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth());
601 return llvm::ConstantInt::get(llvmType, value);
602 }
603 if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
604 const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
605 // Special case for 8-bit floats, which are represented by integers due to
606 // the lack of native fp8 types in LLVM at the moment. Additionally, handle
607 // targets (like AMDGPU) that don't implement bfloat and convert all bfloats
608 // to i16.
609 unsigned floatWidth = APFloat::getSizeInBits(sem);
610 if (llvmType->isIntegerTy(floatWidth))
611 return llvm::ConstantInt::get(llvmType,
612 floatAttr.getValue().bitcastToAPInt());
613 if (llvmType !=
614 llvm::Type::getFloatingPointTy(llvmType->getContext(),
615 floatAttr.getValue().getSemantics())) {
616 emitError(loc, "FloatAttr does not match expected type of the constant");
617 return nullptr;
618 }
619 return llvm::ConstantFP::get(llvmType, floatAttr.getValue());
620 }
621 if (auto symAttr = dyn_cast<FlatSymbolRefAttr>(attr)) {
622 StringRef name = symAttr.getValue();
623 if (llvm::Function *func = moduleTranslation.lookupFunction(name))
624 return llvm::ConstantExpr::getBitCast(func, llvmType);
625 if (llvm::GlobalValue *global = moduleTranslation.lookupGlobal(name))
626 return llvm::ConstantExpr::getBitCast(global, llvmType);
627 emitError(loc, "unknown symbol reference '") << name << "' in constant";
628 return nullptr;
629 }
630 if (auto splatAttr = dyn_cast<SplatElementsAttr>(attr)) {
631 llvm::Type *elementType;
632 uint64_t numElements;
633 bool isScalable = false;
634 if (auto *arrayTy = dyn_cast<llvm::ArrayType>(llvmType)) {
635 elementType = arrayTy->getElementType();
636 numElements = arrayTy->getNumElements();
637 } else if (auto *fVectorTy = dyn_cast<llvm::FixedVectorType>(llvmType)) {
638 elementType = fVectorTy->getElementType();
639 numElements = fVectorTy->getNumElements();
640 } else if (auto *sVectorTy = dyn_cast<llvm::ScalableVectorType>(llvmType)) {
641 elementType = sVectorTy->getElementType();
642 numElements = sVectorTy->getMinNumElements();
643 isScalable = true;
644 } else {
645 llvm_unreachable("unrecognized constant vector type");
646 }
647 // Splat value is a scalar. Extract it only if the element type is not
648 // another sequence type. The recursion terminates because each step removes
649 // one outer sequential type.
650 bool elementTypeSequential =
651 isa<llvm::ArrayType, llvm::VectorType>(elementType);
652 llvm::Constant *child = getLLVMConstant(
653 elementType,
654 elementTypeSequential ? splatAttr
655 : splatAttr.getSplatValue<Attribute>(),
656 loc, moduleTranslation);
657 if (!child)
658 return nullptr;
659 if (llvmType->isVectorTy())
660 return llvm::ConstantVector::getSplat(
661 llvm::ElementCount::get(numElements, /*Scalable=*/isScalable), child);
662 if (llvmType->isArrayTy()) {
663 auto *arrayType = llvm::ArrayType::get(elementType, numElements);
664 if (child->isNullValue() && !elementType->isFPOrFPVectorTy()) {
665 return llvm::ConstantAggregateZero::get(arrayType);
666 }
667 if (llvm::ConstantDataSequential::isElementTypeCompatible(elementType)) {
668 if (isa<llvm::IntegerType>(elementType)) {
669 if (llvm::ConstantInt *ci = dyn_cast<llvm::ConstantInt>(child)) {
670 if (ci->getBitWidth() == 8) {
671 SmallVector<int8_t> constants(numElements, ci->getZExtValue());
672 return llvm::ConstantDataArray::get(elementType->getContext(),
673 constants);
674 }
675 if (ci->getBitWidth() == 16) {
676 SmallVector<int16_t> constants(numElements, ci->getZExtValue());
677 return llvm::ConstantDataArray::get(elementType->getContext(),
678 constants);
679 }
680 if (ci->getBitWidth() == 32) {
681 SmallVector<int32_t> constants(numElements, ci->getZExtValue());
682 return llvm::ConstantDataArray::get(elementType->getContext(),
683 constants);
684 }
685 if (ci->getBitWidth() == 64) {
686 SmallVector<int64_t> constants(numElements, ci->getZExtValue());
687 return llvm::ConstantDataArray::get(elementType->getContext(),
688 constants);
689 }
690 }
691 }
692 if (elementType->isFloatingPointTy()) {
693 if (llvm::ConstantFP *cfp = dyn_cast<llvm::ConstantFP>(child)) {
694 APInt bitPattern = cfp->getValueAPF().bitcastToAPInt();
695 uint64_t value = bitPattern.getZExtValue();
696 // TODO: This code only handles 16, 32, and 64 bit floats. Handle
697 // all compatible types, fp8, fp4, etc.
698 if (bitPattern.getBitWidth() == 16) {
699 SmallVector<uint16_t> constants(numElements, value);
700 return llvm::ConstantDataArray::getFP(elementType, constants);
701 }
702 if (bitPattern.getBitWidth() == 32) {
703 SmallVector<uint32_t> constants(numElements, value);
704 return llvm::ConstantDataArray::getFP(elementType, constants);
705 }
706 if (bitPattern.getBitWidth() == 64) {
707 SmallVector<uint64_t> constants(numElements, value);
708 return llvm::ConstantDataArray::getFP(elementType, constants);
709 }
710 }
711 }
712 }
713 // std::vector is used here to accomodate large number of elements that
714 // exceed SmallVector capacity.
715 std::vector<llvm::Constant *> constants(numElements, child);
716 return llvm::ConstantArray::get(arrayType, constants);
717 }
718 }
719
720 // Try using raw elements data if possible.
721 if (llvm::Constant *result =
722 convertDenseElementsAttr(loc, dyn_cast<DenseElementsAttr>(attr),
723 llvmType, moduleTranslation)) {
724 return result;
725 }
726
727 if (auto denseResourceAttr = dyn_cast<DenseResourceElementsAttr>(attr)) {
728 return convertDenseResourceElementsAttr(loc, denseResourceAttr, llvmType,
729 moduleTranslation);
730 }
731
732 // Fall back to element-by-element construction otherwise.
733 if (auto elementsAttr = dyn_cast<ElementsAttr>(attr)) {
734 assert(elementsAttr.getShapedType().hasStaticShape());
735 assert(!elementsAttr.getShapedType().getShape().empty() &&
736 "unexpected empty elements attribute shape");
737
738 SmallVector<llvm::Constant *, 8> constants;
739 constants.reserve(elementsAttr.getNumElements());
740 llvm::Type *innermostType = getInnermostElementType(llvmType);
741 for (auto n : elementsAttr.getValues<Attribute>()) {
742 constants.push_back(
743 getLLVMConstant(innermostType, n, loc, moduleTranslation));
744 if (!constants.back())
745 return nullptr;
746 }
747 ArrayRef<llvm::Constant *> constantsRef = constants;
748 llvm::Constant *result = buildSequentialConstant(
749 constantsRef, elementsAttr.getShapedType().getShape(), llvmType, loc);
750 assert(constantsRef.empty() && "did not consume all elemental constants");
751 return result;
752 }
753
754 if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
755 return llvm::ConstantDataArray::get(moduleTranslation.getLLVMContext(),
756 ArrayRef<char>{stringAttr.getValue()});
757 }
758
759 // Handle arrays of structs that cannot be represented as DenseElementsAttr
760 // in MLIR.
761 if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
762 if (auto *arrayTy = dyn_cast<llvm::ArrayType>(llvmType)) {
763 llvm::Type *elementType = arrayTy->getElementType();
764 Attribute previousElementAttr;
765 llvm::Constant *elementCst = nullptr;
766 SmallVector<llvm::Constant *> constants;
767 constants.reserve(arrayTy->getNumElements());
768 for (Attribute elementAttr : arrayAttr) {
769 // Arrays with a single value or with repeating values are quite common.
770 // Short-circuit the translation when the element value is the same as
771 // the previous one.
772 if (!previousElementAttr || previousElementAttr != elementAttr) {
773 previousElementAttr = elementAttr;
774 elementCst =
775 getLLVMConstant(elementType, elementAttr, loc, moduleTranslation);
776 if (!elementCst)
777 return nullptr;
778 }
779 constants.push_back(elementCst);
780 }
781 return llvm::ConstantArray::get(arrayTy, constants);
782 }
783 }
784
785 emitError(loc, "unsupported constant value");
786 return nullptr;
787}
788
789ModuleTranslation::ModuleTranslation(Operation *module,
790 std::unique_ptr<llvm::Module> llvmModule,
791 llvm::vfs::FileSystem *fs)
792 : mlirModule(module), llvmModule(std::move(llvmModule)),
793 debugTranslation(
794 std::make_unique<DebugTranslation>(module, *this->llvmModule)),
795 loopAnnotationTranslation(std::make_unique<LoopAnnotationTranslation>(
796 *this, *this->llvmModule)),
797 fileSystem(fs), typeTranslator(this->llvmModule->getContext()),
798 iface(module->getContext()) {
799 assert(satisfiesLLVMModule(mlirModule) &&
800 "mlirModule should honor LLVM's module semantics.");
801}
802
803ModuleTranslation::~ModuleTranslation() {
804 if (ompBuilder && !ompBuilder->isFinalized())
805 ompBuilder->finalize();
806}
807
809 SmallVector<Region *> toProcess;
810 toProcess.push_back(&region);
811 while (!toProcess.empty()) {
812 Region *current = toProcess.pop_back_val();
813 for (Block &block : *current) {
814 blockMapping.erase(&block);
815 for (Value arg : block.getArguments())
816 valueMapping.erase(arg);
817 for (Operation &op : block) {
818 for (Value value : op.getResults())
819 valueMapping.erase(value);
820 if (op.hasSuccessors())
821 branchMapping.erase(&op);
822 if (isa<LLVM::GlobalOp>(op))
823 globalsMapping.erase(&op);
824 if (isa<LLVM::AliasOp>(op))
825 aliasesMapping.erase(&op);
826 if (isa<LLVM::IFuncOp>(op))
827 ifuncMapping.erase(&op);
828 if (isa<LLVM::CallOp>(op))
829 callMapping.erase(&op);
830 llvm::append_range(
831 toProcess,
832 llvm::map_range(op.getRegions(), [](Region &r) { return &r; }));
833 }
834 }
835 }
836}
837
838/// Get the SSA value passed to the current block from the terminator operation
839/// of its predecessor.
840static Value getPHISourceValue(Block *current, Block *pred,
841 unsigned numArguments, unsigned index) {
842 Operation &terminator = *pred->getTerminator();
843 if (isa<LLVM::BrOp>(terminator))
844 return terminator.getOperand(index);
845
846#ifndef NDEBUG
847 llvm::SmallPtrSet<Block *, 4> seenSuccessors;
848 for (unsigned i = 0, e = terminator.getNumSuccessors(); i < e; ++i) {
849 Block *successor = terminator.getSuccessor(i);
850 auto branch = cast<BranchOpInterface>(terminator);
851 SuccessorOperands successorOperands = branch.getSuccessorOperands(i);
852 assert(
853 (!seenSuccessors.contains(successor) || successorOperands.empty()) &&
854 "successors with arguments in LLVM branches must be different blocks");
855 seenSuccessors.insert(successor);
856 }
857#endif
858
859 // For instructions that branch based on a condition value, we need to take
860 // the operands for the branch that was taken.
861 if (auto condBranchOp = dyn_cast<LLVM::CondBrOp>(terminator)) {
862 // For conditional branches, we take the operands from either the "true" or
863 // the "false" branch.
864 return condBranchOp.getSuccessor(0) == current
865 ? condBranchOp.getTrueDestOperands()[index]
866 : condBranchOp.getFalseDestOperands()[index];
867 }
868
869 if (auto switchOp = dyn_cast<LLVM::SwitchOp>(terminator)) {
870 // For switches, we take the operands from either the default case, or from
871 // the case branch that was taken.
872 if (switchOp.getDefaultDestination() == current)
873 return switchOp.getDefaultOperands()[index];
874 for (const auto &i : llvm::enumerate(switchOp.getCaseDestinations()))
875 if (i.value() == current)
876 return switchOp.getCaseOperands(i.index())[index];
877 }
878
879 if (auto indBrOp = dyn_cast<LLVM::IndirectBrOp>(terminator)) {
880 // For indirect branches we take operands for each successor.
881 for (const auto &i : llvm::enumerate(indBrOp->getSuccessors())) {
882 if (indBrOp->getSuccessor(i.index()) == current)
883 return indBrOp.getSuccessorOperands(i.index())[index];
884 }
885 }
886
887 if (auto invokeOp = dyn_cast<LLVM::InvokeOp>(terminator)) {
888 return invokeOp.getNormalDest() == current
889 ? invokeOp.getNormalDestOperands()[index]
890 : invokeOp.getUnwindDestOperands()[index];
891 }
892
893 llvm_unreachable(
894 "only branch, switch or invoke operations can be terminators "
895 "of a block that has successors");
896}
897
898/// Connect the PHI nodes to the results of preceding blocks.
900 const ModuleTranslation &state) {
901 // Skip the first block, it cannot be branched to and its arguments correspond
902 // to the arguments of the LLVM function.
903 for (Block &bb : llvm::drop_begin(region)) {
904 llvm::BasicBlock *llvmBB = state.lookupBlock(&bb);
905 auto phis = llvmBB->phis();
906 auto numArguments = bb.getNumArguments();
907 assert(numArguments == std::distance(phis.begin(), phis.end()));
908 for (auto [index, phiNode] : llvm::enumerate(phis)) {
909 for (auto *pred : bb.getPredecessors()) {
910 // Find the LLVM IR block that contains the converted terminator
911 // instruction and use it in the PHI node. Note that this block is not
912 // necessarily the same as state.lookupBlock(pred), some operations
913 // (in particular, OpenMP operations using OpenMPIRBuilder) may have
914 // split the blocks.
915 llvm::Instruction *terminator =
916 state.lookupBranch(pred->getTerminator());
917 assert(terminator && "missing the mapping for a terminator");
918 phiNode.addIncoming(state.lookupValue(getPHISourceValue(
919 &bb, pred, numArguments, index)),
920 terminator->getParent());
921 }
922 }
923 }
924}
925
927 llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
929 return builder.CreateIntrinsic(intrinsic, tys, args);
930}
931
933 llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
934 llvm::Type *retTy, ArrayRef<llvm::Value *> args) {
935 return builder.CreateIntrinsic(retTy, intrinsic, args);
936}
937
939 llvm::IRBuilderBase &builder, ModuleTranslation &moduleTranslation,
940 Operation *intrOp, llvm::Intrinsic::ID intrinsic, unsigned numResults,
941 ArrayRef<unsigned> overloadedResults, ArrayRef<unsigned> overloadedOperands,
942 ArrayRef<unsigned> immArgPositions,
943 ArrayRef<StringLiteral> immArgAttrNames) {
944 assert(immArgPositions.size() == immArgAttrNames.size() &&
945 "LLVM `immArgPositions` and MLIR `immArgAttrNames` should have equal "
946 "length");
947
949 size_t numOpBundleOperands = 0;
950 auto opBundleSizesAttr = cast_if_present<DenseI32ArrayAttr>(
951 intrOp->getAttr(LLVMDialect::getOpBundleSizesAttrName()));
952 auto opBundleTagsAttr = cast_if_present<ArrayAttr>(
953 intrOp->getAttr(LLVMDialect::getOpBundleTagsAttrName()));
954
955 if (opBundleSizesAttr && opBundleTagsAttr) {
956 ArrayRef<int> opBundleSizes = opBundleSizesAttr.asArrayRef();
957 assert(opBundleSizes.size() == opBundleTagsAttr.size() &&
958 "operand bundles and tags do not match");
959
960 numOpBundleOperands = llvm::sum_of(opBundleSizes);
961 assert(numOpBundleOperands <= intrOp->getNumOperands() &&
962 "operand bundle operands is more than the number of operands");
963
964 ValueRange operands = intrOp->getOperands().take_back(numOpBundleOperands);
965 size_t nextOperandIdx = 0;
966 opBundles.reserve(opBundleSizesAttr.size());
967
968 for (auto [opBundleTagAttr, bundleSize] :
969 llvm::zip(opBundleTagsAttr, opBundleSizes)) {
970 auto bundleTag = cast<StringAttr>(opBundleTagAttr).str();
971 auto bundleOperands = moduleTranslation.lookupValues(
972 operands.slice(nextOperandIdx, bundleSize));
973 opBundles.emplace_back(std::move(bundleTag), std::move(bundleOperands));
974 nextOperandIdx += bundleSize;
975 }
976 }
977
978 // Map operands and attributes to LLVM values.
979 auto opOperands = intrOp->getOperands().drop_back(numOpBundleOperands);
980 auto operands = moduleTranslation.lookupValues(opOperands);
981 SmallVector<llvm::Value *> args(immArgPositions.size() + operands.size());
982 for (auto [immArgPos, immArgName] :
983 llvm::zip(immArgPositions, immArgAttrNames)) {
984 auto attr = llvm::cast<TypedAttr>(intrOp->getAttr(immArgName));
985 assert(attr.getType().isIntOrFloat() && "expected int or float immarg");
986 auto *type = moduleTranslation.convertType(attr.getType());
987 args[immArgPos] = LLVM::detail::getLLVMConstant(
988 type, attr, intrOp->getLoc(), moduleTranslation);
989 }
990 unsigned opArg = 0;
991 for (auto &arg : args) {
992 if (!arg)
993 arg = operands[opArg++];
994 }
995
996 // Resolve overloaded intrinsic declaration.
997 SmallVector<llvm::Type *> overloadedTypes;
998 for (unsigned overloadedResultIdx : overloadedResults) {
999 if (numResults > 1) {
1000 // More than one result is mapped to an LLVM struct.
1001 overloadedTypes.push_back(moduleTranslation.convertType(
1002 llvm::cast<LLVM::LLVMStructType>(intrOp->getResult(0).getType())
1003 .getBody()[overloadedResultIdx]));
1004 } else {
1005 overloadedTypes.push_back(
1006 moduleTranslation.convertType(intrOp->getResult(0).getType()));
1007 }
1008 }
1009 for (unsigned overloadedOperandIdx : overloadedOperands)
1010 overloadedTypes.push_back(args[overloadedOperandIdx]->getType());
1011 llvm::Module *module = builder.GetInsertBlock()->getModule();
1012 llvm::Function *llvmIntr = llvm::Intrinsic::getOrInsertDeclaration(
1013 module, intrinsic, overloadedTypes);
1014
1015 return builder.CreateCall(llvmIntr, args, opBundles);
1016}
1017
1018/// Given a single MLIR operation, create the corresponding LLVM IR operation
1019/// using the `builder`.
1020LogicalResult ModuleTranslation::convertOperationImpl(
1021 Operation &op, llvm::IRBuilderBase &builder, bool recordInsertions) {
1022 const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor(&op);
1023 if (!opIface)
1024 return op.emitError("cannot be converted to LLVM IR: missing "
1025 "`LLVMTranslationDialectInterface` registration for "
1026 "dialect for op: ")
1027 << op.getName();
1028
1029 InstructionCapturingInserter::CollectionScope scope(builder,
1030 recordInsertions);
1031 if (failed(opIface->convertOperation(&op, builder, *this)))
1032 return op.emitError("LLVM Translation failed for operation: ")
1033 << op.getName();
1034
1035 return convertDialectAttributes(&op, scope.getCapturedInstructions());
1036}
1037
1038/// Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes
1039/// to define values corresponding to the MLIR block arguments. These nodes
1040/// are not connected to the source basic blocks, which may not exist yet. Uses
1041/// `builder` to construct the LLVM IR. Expects the LLVM IR basic block to have
1042/// been created for `bb` and included in the block mapping. Inserts new
1043/// instructions at the end of the block and leaves `builder` in a state
1044/// suitable for further insertion into the end of the block.
1045LogicalResult ModuleTranslation::convertBlockImpl(Block &bb,
1046 bool ignoreArguments,
1047 llvm::IRBuilderBase &builder,
1048 bool recordInsertions) {
1049 builder.SetInsertPoint(lookupBlock(&bb));
1050 auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
1051
1052 // Before traversing operations, make block arguments available through
1053 // value remapping and PHI nodes, but do not add incoming edges for the PHI
1054 // nodes just yet: those values may be defined by this or following blocks.
1055 // This step is omitted if "ignoreArguments" is set. The arguments of the
1056 // first block have been already made available through the remapping of
1057 // LLVM function arguments.
1058 if (!ignoreArguments) {
1059 auto predecessors = bb.getPredecessors();
1060 unsigned numPredecessors =
1061 std::distance(predecessors.begin(), predecessors.end());
1062 for (auto arg : bb.getArguments()) {
1063 auto wrappedType = arg.getType();
1064 if (!isCompatibleType(wrappedType))
1065 return emitError(bb.front().getLoc(),
1066 "block argument does not have an LLVM type");
1067 builder.SetCurrentDebugLocation(
1068 debugTranslation->translateLoc(arg.getLoc(), subprogram));
1069 llvm::Type *type = convertType(wrappedType);
1070 llvm::PHINode *phi = builder.CreatePHI(type, numPredecessors);
1071 mapValue(arg, phi);
1072 }
1073 }
1074
1075 // Traverse operations.
1076 for (auto &op : bb) {
1077 // Set the current debug location within the builder.
1078 builder.SetCurrentDebugLocation(
1079 debugTranslation->translateLoc(op.getLoc(), subprogram));
1080
1081 if (failed(convertOperationImpl(op, builder, recordInsertions)))
1082 return failure();
1083
1084 // Set the branch weight metadata on the translated instruction.
1085 if (auto iface = dyn_cast<WeightedBranchOpInterface>(op))
1087 }
1088
1089 return success();
1090}
1091
1092/// A helper method to get the single Block in an operation honoring LLVM's
1093/// module requirements.
1095 return module->getRegion(0).front();
1096}
1097
1098/// A helper method to decide if a constant must not be set as a global variable
1099/// initializer. For an external linkage variable, the variable with an
1100/// initializer is considered externally visible and defined in this module, the
1101/// variable without an initializer is externally available and is defined
1102/// elsewhere.
1103static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage,
1104 llvm::Constant *cst) {
1105 return (linkage == llvm::GlobalVariable::ExternalLinkage && !cst) ||
1106 linkage == llvm::GlobalVariable::ExternalWeakLinkage;
1107}
1108
1109/// Sets the runtime preemption specifier of `gv` to dso_local if
1110/// `dsoLocalRequested` is true, otherwise it is left unchanged.
1111static void addRuntimePreemptionSpecifier(bool dsoLocalRequested,
1112 llvm::GlobalValue *gv) {
1113 if (dsoLocalRequested)
1114 gv->setDSOLocal(true);
1115}
1116
1117/// Attempts to translate an MLIR attribute identified by `key`, optionally with
1118/// the given `value`, into an LLVM IR attribute. Reports errors at `loc` if
1119/// any. If the attribute name corresponds to a known LLVM IR attribute kind,
1120/// creates the LLVM attribute of that kind; otherwise, keeps it as a string
1121/// attribute. Performs additional checks for attributes known to have or not
1122/// have a value in order to avoid assertions inside LLVM upon construction.
1123static FailureOr<llvm::Attribute>
1124convertMLIRAttributeToLLVM(Location loc, llvm::LLVMContext &ctx, StringRef key,
1125 StringRef value = StringRef()) {
1126 auto kind = llvm::Attribute::getAttrKindFromName(key);
1127 if (kind == llvm::Attribute::None)
1128 return llvm::Attribute::get(ctx, key, value);
1129
1130 if (llvm::Attribute::isIntAttrKind(kind)) {
1131 if (value.empty())
1132 return emitError(loc) << "LLVM attribute '" << key << "' expects a value";
1133
1135 if (!value.getAsInteger(/*Radix=*/0, result))
1136 return llvm::Attribute::get(ctx, kind, result);
1137 return llvm::Attribute::get(ctx, key, value);
1138 }
1139
1140 if (!value.empty())
1141 return emitError(loc) << "LLVM attribute '" << key
1142 << "' does not expect a value, found '" << value
1143 << "'";
1144
1145 return llvm::Attribute::get(ctx, kind);
1146}
1147
1148/// Converts the MLIR attributes listed in the given array attribute into LLVM
1149/// attributes. Returns an `AttrBuilder` containing the converted attributes.
1150/// Reports error to `loc` if any and returns immediately. Expects `arrayAttr`
1151/// to contain either string attributes, treated as value-less LLVM attributes,
1152/// or array attributes containing two string attributes, with the first string
1153/// being the name of the corresponding LLVM attribute and the second string
1154/// beings its value. Note that even integer attributes are expected to have
1155/// their values expressed as strings.
1156static FailureOr<llvm::AttrBuilder>
1157convertMLIRAttributesToLLVM(Location loc, llvm::LLVMContext &ctx,
1158 ArrayAttr arrayAttr, StringRef arrayAttrName) {
1159 llvm::AttrBuilder attrBuilder(ctx);
1160 if (!arrayAttr)
1161 return attrBuilder;
1162
1163 for (Attribute attr : arrayAttr) {
1164 if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
1165 FailureOr<llvm::Attribute> llvmAttr =
1166 convertMLIRAttributeToLLVM(loc, ctx, stringAttr.getValue());
1167 if (failed(llvmAttr))
1168 return failure();
1169 attrBuilder.addAttribute(*llvmAttr);
1170 continue;
1171 }
1172
1173 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1174 if (!arrayAttr || arrayAttr.size() != 2)
1175 return emitError(loc) << "expected '" << arrayAttrName
1176 << "' to contain string or array attributes";
1177
1178 auto keyAttr = dyn_cast<StringAttr>(arrayAttr[0]);
1179 auto valueAttr = dyn_cast<StringAttr>(arrayAttr[1]);
1180 if (!keyAttr || !valueAttr)
1181 return emitError(loc) << "expected arrays within '" << arrayAttrName
1182 << "' to contain two strings";
1183
1184 FailureOr<llvm::Attribute> llvmAttr = convertMLIRAttributeToLLVM(
1185 loc, ctx, keyAttr.getValue(), valueAttr.getValue());
1186 if (failed(llvmAttr))
1187 return failure();
1188 attrBuilder.addAttribute(*llvmAttr);
1189 }
1190
1191 return attrBuilder;
1192}
1193
1194LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
1195 // Mapping from compile unit to its respective set of global variables.
1197
1198 // First, create all global variables and global aliases in LLVM IR. A global
1199 // or alias body may refer to another global/alias or itself, so all the
1200 // mapping needs to happen prior to body conversion.
1201
1202 // Create all llvm::GlobalVariable
1203 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1204 llvm::Type *type = convertType(op.getType());
1205 llvm::Constant *cst = nullptr;
1206 const bool deferValueAttrToPass2 = op.getValueOrNull() &&
1207 !op.getInitializerBlock() &&
1208 !isa<StringAttr>(op.getValueOrNull());
1209 if (op.getValueOrNull() && !deferValueAttrToPass2) {
1210 // String attributes are treated separately because they cannot appear as
1211 // in-function constants and are thus not supported by getLLVMConstant.
1212 if (auto strAttr = dyn_cast_or_null<StringAttr>(op.getValueOrNull())) {
1213 cst = llvm::ConstantDataArray::getString(
1214 llvmModule->getContext(), strAttr.getValue(), /*AddNull=*/false);
1215 type = cst->getType();
1216 }
1217 }
1218
1219 auto linkage = convertLinkageToLLVM(op.getLinkage());
1220
1221 // LLVM IR requires constant with linkage other than external or weak
1222 // external to have initializers. If MLIR does not provide an initializer,
1223 // default to undef.
1224 bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
1225 if (!deferValueAttrToPass2) {
1226 if (!dropInitializer && !cst)
1227 cst = llvm::UndefValue::get(type);
1228 else if (dropInitializer && cst)
1229 cst = nullptr;
1230 } else {
1231 cst = nullptr;
1232 }
1233
1234 auto *var = new llvm::GlobalVariable(
1235 *llvmModule, type, op.getConstant(), linkage, cst, op.getSymName(),
1236 /*InsertBefore=*/nullptr,
1237 op.getThreadLocal_() ? llvm::GlobalValue::GeneralDynamicTLSModel
1238 : llvm::GlobalValue::NotThreadLocal,
1239 op.getAddrSpace(), op.getExternallyInitialized());
1240
1241 if (std::optional<mlir::SymbolRefAttr> comdat = op.getComdat()) {
1242 auto selectorOp = cast<ComdatSelectorOp>(
1244 var->setComdat(comdatMapping.lookup(selectorOp));
1245 }
1246
1247 if (op.getUnnamedAddr().has_value())
1248 var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
1249
1250 if (op.getSection().has_value())
1251 var->setSection(*op.getSection());
1252
1253 addRuntimePreemptionSpecifier(op.getDsoLocal(), var);
1254
1255 std::optional<uint64_t> alignment = op.getAlignment();
1256 if (alignment.has_value())
1257 var->setAlignment(llvm::MaybeAlign(alignment.value()));
1258
1259 var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
1260
1261 globalsMapping.try_emplace(op, var);
1262 globalsByNameMapping.try_emplace(op.getSymName(), var);
1263
1264 // Add debug information if present.
1265 if (op.getDbgExprs()) {
1266 for (auto exprAttr :
1267 op.getDbgExprs()->getAsRange<DIGlobalVariableExpressionAttr>()) {
1268 llvm::DIGlobalVariableExpression *diGlobalExpr =
1269 debugTranslation->translateGlobalVariableExpression(exprAttr);
1270 llvm::DIGlobalVariable *diGlobalVar = diGlobalExpr->getVariable();
1271 var->addDebugInfo(diGlobalExpr);
1272
1273 // There is no `globals` field in DICompileUnitAttr which can be
1274 // directly assigned to DICompileUnit. We have to build the list by
1275 // looking at the dbgExpr of all the GlobalOps. The scope of the
1276 // variable is used to get the DICompileUnit in which to add it. But
1277 // there are cases where the scope of a global does not directly point
1278 // to the DICompileUnit and we have to do a bit more work to get to
1279 // it. Some of those cases are:
1280 //
1281 // 1. For the languages that support modules, the scope hierarchy can
1282 // be variable -> DIModule -> DICompileUnit
1283 //
1284 // 2. For the Fortran common block variable, the scope hierarchy can
1285 // be variable -> DICommonBlock -> DISubprogram -> DICompileUnit
1286 //
1287 // 3. For entities like static local variables in C or variable with
1288 // SAVE attribute in Fortran, the scope hierarchy can be
1289 // variable -> DISubprogram -> DICompileUnit
1290 llvm::DIScope *scope = diGlobalVar->getScope();
1291 if (auto *mod = dyn_cast_if_present<llvm::DIModule>(scope))
1292 scope = mod->getScope();
1293 else if (auto *cb = dyn_cast_if_present<llvm::DICommonBlock>(scope)) {
1294 if (auto *sp =
1295 dyn_cast_if_present<llvm::DISubprogram>(cb->getScope()))
1296 scope = sp->getUnit();
1297 } else if (auto *sp = dyn_cast_if_present<llvm::DISubprogram>(scope))
1298 scope = sp->getUnit();
1299
1300 // Get the compile unit (scope) of the the global variable.
1301 if (llvm::DICompileUnit *compileUnit =
1302 dyn_cast_if_present<llvm::DICompileUnit>(scope)) {
1303 // Update the compile unit with this incoming global variable
1304 // expression during the finalizing step later.
1305 allGVars[compileUnit].push_back(diGlobalExpr);
1306 }
1307 }
1308 }
1309
1310 // Forward the target-specific attributes to LLVM.
1311 FailureOr<llvm::AttrBuilder> convertedTargetSpecificAttrs =
1313 op.getTargetSpecificAttrsAttr(),
1314 op.getTargetSpecificAttrsAttrName());
1315 if (failed(convertedTargetSpecificAttrs))
1316 return failure();
1317 var->addAttributes(*convertedTargetSpecificAttrs);
1318 }
1319
1320 // Value-attribute initializers may reference other globals by symbol name.
1321 // Register every global above before materializing those constants.
1322 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1323 if (!op.getValueOrNull() || op.getInitializerBlock() ||
1324 isa<StringAttr>(op.getValueOrNull()))
1325 continue;
1326
1327 llvm::Type *type = convertType(op.getType());
1328 llvm::Constant *cst =
1329 getLLVMConstant(type, op.getValueOrNull(), op.getLoc(), *this);
1330 if (!cst)
1331 return failure();
1332
1333 auto linkage = convertLinkageToLLVM(op.getLinkage());
1334 bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
1335 auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
1336 if (dropInitializer)
1337 var->setInitializer(nullptr);
1338 else
1339 var->setInitializer(cst);
1340 }
1341
1342 // Create all llvm::GlobalAlias
1343 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
1344 llvm::Type *type = convertType(op.getType());
1345 llvm::Constant *cst = nullptr;
1346 llvm::GlobalValue::LinkageTypes linkage =
1347 convertLinkageToLLVM(op.getLinkage());
1348 llvm::Module &llvmMod = *llvmModule;
1349
1350 // Note address space and aliasee info isn't set just yet.
1351 llvm::GlobalAlias *var = llvm::GlobalAlias::create(
1352 type, op.getAddrSpace(), linkage, op.getSymName(), /*placeholder*/ cst,
1353 &llvmMod);
1354
1355 var->setThreadLocalMode(op.getThreadLocal_()
1356 ? llvm::GlobalAlias::GeneralDynamicTLSModel
1357 : llvm::GlobalAlias::NotThreadLocal);
1358
1359 // Note there is no need to setup the comdat because GlobalAlias calls into
1360 // the aliasee comdat information automatically.
1361
1362 if (op.getUnnamedAddr().has_value())
1363 var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
1364
1365 var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
1366
1367 aliasesMapping.try_emplace(op, var);
1368 }
1369
1370 // Convert global variable bodies.
1371 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1372 if (Block *initializer = op.getInitializerBlock()) {
1373 llvm::IRBuilder<llvm::TargetFolder> builder(
1374 llvmModule->getContext(),
1375 llvm::TargetFolder(llvmModule->getDataLayout()));
1376
1377 [[maybe_unused]] int numConstantsHit = 0;
1378 [[maybe_unused]] int numConstantsErased = 0;
1379 DenseMap<llvm::ConstantAggregate *, int> constantAggregateUseMap;
1380
1381 for (auto &op : initializer->without_terminator()) {
1382 if (failed(convertOperation(op, builder)))
1383 return emitError(op.getLoc(), "fail to convert global initializer");
1384 auto *cst = dyn_cast<llvm::Constant>(lookupValue(op.getResult(0)));
1385 if (!cst)
1386 return emitError(op.getLoc(), "unemittable constant value");
1387
1388 // When emitting an LLVM constant, a new constant is created and the old
1389 // constant may become dangling and take space. We should remove the
1390 // dangling constants to avoid memory explosion especially for constant
1391 // arrays whose number of elements is large.
1392 // Because multiple operations may refer to the same constant, we need
1393 // to count the number of uses of each constant array and remove it only
1394 // when the count becomes zero.
1395 if (auto *agg = dyn_cast<llvm::ConstantAggregate>(cst)) {
1396 numConstantsHit++;
1397 Value result = op.getResult(0);
1398 int numUsers = std::distance(result.use_begin(), result.use_end());
1399 auto [iterator, inserted] =
1400 constantAggregateUseMap.try_emplace(agg, numUsers);
1401 if (!inserted) {
1402 // Key already exists, update the value
1403 iterator->second += numUsers;
1404 }
1405 }
1406 // Scan the operands of the operation to decrement the use count of
1407 // constants. Erase the constant if the use count becomes zero.
1408 for (Value v : op.getOperands()) {
1409 auto *cst = dyn_cast<llvm::ConstantAggregate>(lookupValue(v));
1410 if (!cst)
1411 continue;
1412 auto iter = constantAggregateUseMap.find(cst);
1413 assert(iter != constantAggregateUseMap.end() && "constant not found");
1414 iter->second--;
1415 if (iter->second == 0) {
1416 // NOTE: cannot call removeDeadConstantUsers() here because it
1417 // may remove the constant which has uses not be converted yet.
1418 if (cst->user_empty()) {
1419 cst->destroyConstant();
1420 numConstantsErased++;
1421 }
1422 constantAggregateUseMap.erase(iter);
1423 }
1424 }
1425 }
1426
1427 ReturnOp ret = cast<ReturnOp>(initializer->getTerminator());
1428 llvm::Constant *cst =
1429 cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
1430 auto *global = cast<llvm::GlobalVariable>(lookupGlobal(op));
1431 if (!shouldDropGlobalInitializer(global->getLinkage(), cst))
1432 global->setInitializer(cst);
1433
1434 // Try to remove the dangling constants again after all operations are
1435 // converted.
1436 for (auto it : constantAggregateUseMap) {
1437 auto *cst = it.first;
1438 cst->removeDeadConstantUsers();
1439 if (cst->user_empty()) {
1440 cst->destroyConstant();
1441 numConstantsErased++;
1442 }
1443 }
1444
1445 LLVM_DEBUG(llvm::dbgs()
1446 << "Convert initializer for " << op.getName() << "\n";
1447 llvm::dbgs() << numConstantsHit << " new constants hit\n";
1448 llvm::dbgs()
1449 << numConstantsErased << " dangling constants erased\n";);
1450 }
1451 }
1452
1453 // Convert llvm.mlir.global_ctors and dtors.
1454 for (Operation &op : getModuleBody(mlirModule)) {
1455 auto ctorOp = dyn_cast<GlobalCtorsOp>(op);
1456 auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
1457 if (!ctorOp && !dtorOp)
1458 continue;
1459
1460 // The empty / zero initialized version of llvm.global_(c|d)tors cannot be
1461 // handled by appendGlobalFn logic below, which just ignores empty (c|d)tor
1462 // lists. Make sure it gets emitted.
1463 if ((ctorOp && ctorOp.getCtors().empty()) ||
1464 (dtorOp && dtorOp.getDtors().empty())) {
1465 llvm::IRBuilder<llvm::TargetFolder> builder(
1466 llvmModule->getContext(),
1467 llvm::TargetFolder(llvmModule->getDataLayout()));
1468 llvm::Type *eltTy = llvm::StructType::get(
1469 builder.getInt32Ty(), builder.getPtrTy(), builder.getPtrTy());
1470 llvm::ArrayType *at = llvm::ArrayType::get(eltTy, 0);
1471 llvm::Constant *zeroInit = llvm::Constant::getNullValue(at);
1472 (void)new llvm::GlobalVariable(
1473 *llvmModule, zeroInit->getType(), false,
1474 llvm::GlobalValue::AppendingLinkage, zeroInit,
1475 ctorOp ? "llvm.global_ctors" : "llvm.global_dtors");
1476 } else {
1477 auto range = ctorOp
1478 ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
1479 : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
1480 auto appendGlobalFn =
1481 ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
1482 for (const auto &[sym, prio] : range) {
1483 llvm::Function *f =
1484 lookupFunction(cast<FlatSymbolRefAttr>(sym).getValue());
1485 appendGlobalFn(*llvmModule, f, cast<IntegerAttr>(prio).getInt(),
1486 /*Data=*/nullptr);
1487 }
1488 }
1489 }
1490
1491 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>())
1492 if (failed(convertDialectAttributes(op, {})))
1493 return failure();
1494
1495 // Finally, update the compile units their respective sets of global variables
1496 // created earlier.
1497 for (const auto &[compileUnit, globals] : allGVars) {
1498 compileUnit->replaceGlobalVariables(
1499 llvm::MDTuple::get(getLLVMContext(), globals));
1500 }
1501
1502 // Convert global alias bodies.
1503 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
1504 Block &initializer = op.getInitializerBlock();
1505 llvm::IRBuilder<llvm::TargetFolder> builder(
1506 llvmModule->getContext(),
1507 llvm::TargetFolder(llvmModule->getDataLayout()));
1508
1509 for (mlir::Operation &op : initializer.without_terminator()) {
1510 if (failed(convertOperation(op, builder)))
1511 return emitError(op.getLoc(), "fail to convert alias initializer");
1512 if (!isa<llvm::Constant>(lookupValue(op.getResult(0))))
1513 return emitError(op.getLoc(), "unemittable constant value");
1514 }
1515
1516 auto ret = cast<ReturnOp>(initializer.getTerminator());
1517 auto *cst = cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
1518 assert(aliasesMapping.count(op));
1519 auto *alias = cast<llvm::GlobalAlias>(aliasesMapping[op]);
1520 alias->setAliasee(cst);
1521 }
1522
1523 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>())
1524 if (failed(convertDialectAttributes(op, {})))
1525 return failure();
1526
1527 return success();
1528}
1529
1530/// Return a representation of `value` as metadata.
1531static llvm::Metadata *convertIntegerToMetadata(llvm::LLVMContext &context,
1532 const llvm::APInt &value) {
1533 llvm::Constant *constant = llvm::ConstantInt::get(context, value);
1534 return llvm::ConstantAsMetadata::get(constant);
1535}
1536
1537/// Return a representation of `value` as an MDNode.
1538static llvm::MDNode *convertIntegerToMDNode(llvm::LLVMContext &context,
1539 const llvm::APInt &value) {
1540 return llvm::MDNode::get(context, convertIntegerToMetadata(context, value));
1541}
1542
1543/// Return an MDNode encoding `vec_type_hint` metadata.
1544static llvm::MDNode *convertVecTypeHintToMDNode(llvm::LLVMContext &context,
1545 llvm::Type *type,
1546 bool isSigned) {
1547 llvm::Metadata *typeMD =
1548 llvm::ConstantAsMetadata::get(llvm::UndefValue::get(type));
1549 llvm::Metadata *isSignedMD =
1550 convertIntegerToMetadata(context, llvm::APInt(32, isSigned ? 1 : 0));
1551 return llvm::MDNode::get(context, {typeMD, isSignedMD});
1552}
1553
1554/// Return an MDNode with a tuple given by the values in `values`.
1555static llvm::MDNode *convertIntegerArrayToMDNode(llvm::LLVMContext &context,
1556 ArrayRef<int32_t> values) {
1558 llvm::transform(
1559 values, std::back_inserter(mdValues), [&context](int32_t value) {
1560 return convertIntegerToMetadata(context, llvm::APInt(32, value));
1561 });
1562 return llvm::MDNode::get(context, mdValues);
1563}
1564
1565LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
1566 // Clear the block, branch value mappings, they are only relevant within one
1567 // function.
1568 blockMapping.clear();
1569 valueMapping.clear();
1570 branchMapping.clear();
1571 llvm::Function *llvmFunc = lookupFunction(func.getName());
1572 llvm::LLVMContext &llvmContext = llvmFunc->getContext();
1573
1574 // Add function arguments to the value remapping table.
1575 for (auto [mlirArg, llvmArg] :
1576 llvm::zip(func.getArguments(), llvmFunc->args()))
1577 mapValue(mlirArg, &llvmArg);
1578
1579 // Check the personality and set it.
1580 if (func.getPersonality()) {
1581 llvm::Type *ty = llvm::PointerType::getUnqual(llvmFunc->getContext());
1582 if (llvm::Constant *pfunc = getLLVMConstant(ty, func.getPersonalityAttr(),
1583 func.getLoc(), *this))
1584 llvmFunc->setPersonalityFn(pfunc);
1585 }
1586
1587 if (std::optional<StringRef> section = func.getSection())
1588 llvmFunc->setSection(*section);
1589
1590 if (func.getArmStreaming())
1591 llvmFunc->addFnAttr("aarch64_pstate_sm_enabled");
1592 else if (func.getArmLocallyStreaming())
1593 llvmFunc->addFnAttr("aarch64_pstate_sm_body");
1594 else if (func.getArmStreamingCompatible())
1595 llvmFunc->addFnAttr("aarch64_pstate_sm_compatible");
1596
1597 if (func.getArmNewZa())
1598 llvmFunc->addFnAttr("aarch64_new_za");
1599 else if (func.getArmInZa())
1600 llvmFunc->addFnAttr("aarch64_in_za");
1601 else if (func.getArmOutZa())
1602 llvmFunc->addFnAttr("aarch64_out_za");
1603 else if (func.getArmInoutZa())
1604 llvmFunc->addFnAttr("aarch64_inout_za");
1605 else if (func.getArmPreservesZa())
1606 llvmFunc->addFnAttr("aarch64_preserves_za");
1607
1608 if (auto targetCpu = func.getTargetCpu())
1609 llvmFunc->addFnAttr("target-cpu", *targetCpu);
1610
1611 if (auto tuneCpu = func.getTuneCpu())
1612 llvmFunc->addFnAttr("tune-cpu", *tuneCpu);
1613
1614 if (auto reciprocalEstimates = func.getReciprocalEstimates())
1615 llvmFunc->addFnAttr("reciprocal-estimates", *reciprocalEstimates);
1616
1617 if (auto preferVectorWidth = func.getPreferVectorWidth())
1618 llvmFunc->addFnAttr("prefer-vector-width", *preferVectorWidth);
1619
1620 if (func.getUseSampleProfile())
1621 llvmFunc->addFnAttr("use-sample-profile");
1622
1623 if (auto attr = func.getVscaleRange())
1624 llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
1625 getLLVMContext(), attr->getMinRange().getInt(),
1626 attr->getMaxRange().getInt()));
1627
1628 if (auto noSignedZerosFpMath = func.getNoSignedZerosFpMath())
1629 llvmFunc->addFnAttr("no-signed-zeros-fp-math",
1630 llvm::toStringRef(*noSignedZerosFpMath));
1631
1632 if (auto fpContract = func.getFpContract())
1633 llvmFunc->addFnAttr("fp-contract", *fpContract);
1634
1635 if (auto instrumentFunctionEntry = func.getInstrumentFunctionEntry())
1636 llvmFunc->addFnAttr("instrument-function-entry", *instrumentFunctionEntry);
1637
1638 if (auto instrumentFunctionExit = func.getInstrumentFunctionExit())
1639 llvmFunc->addFnAttr("instrument-function-exit", *instrumentFunctionExit);
1640
1641 // First, create all blocks so we can jump to them.
1642 for (auto &bb : func) {
1643 auto *llvmBB = llvm::BasicBlock::Create(llvmContext);
1644 llvmBB->insertInto(llvmFunc);
1645 mapBlock(&bb, llvmBB);
1646 }
1647
1648 // Then, convert blocks one by one in topological order to ensure defs are
1649 // converted before uses.
1650 auto blocks = getBlocksSortedByDominance(func.getBody());
1651 for (Block *bb : blocks) {
1652 CapturingIRBuilder builder(llvmContext,
1653 llvm::TargetFolder(llvmModule->getDataLayout()));
1654 if (failed(convertBlockImpl(*bb, bb->isEntryBlock(), builder,
1655 /*recordInsertions=*/true)))
1656 return failure();
1657 }
1658
1659 // After all blocks have been traversed and values mapped, connect the PHI
1660 // nodes to the results of preceding blocks.
1661 detail::connectPHINodes(func.getBody(), *this);
1662
1663 // Finally, convert dialect attributes attached to the function.
1664 return convertDialectAttributes(func, {});
1665}
1666
1667LogicalResult ModuleTranslation::convertDialectAttributes(
1668 Operation *op, ArrayRef<llvm::Instruction *> instructions) {
1669 for (NamedAttribute attribute : op->getDialectAttrs())
1670 if (failed(iface.amendOperation(op, instructions, attribute, *this)))
1671 return failure();
1672 return success();
1673}
1674
1675/// Converts memory effect attributes from `func` and attaches them to
1676/// `llvmFunc`.
1678 llvm::Function *llvmFunc) {
1679 if (!func.getMemoryEffects())
1680 return;
1681
1682 MemoryEffectsAttr memEffects = func.getMemoryEffectsAttr();
1683
1684 // Add memory effects incrementally.
1685 llvm::MemoryEffects newMemEffects =
1686 llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
1687 convertModRefInfoToLLVM(memEffects.getArgMem()));
1688 newMemEffects |= llvm::MemoryEffects(
1689 llvm::MemoryEffects::Location::InaccessibleMem,
1690 convertModRefInfoToLLVM(memEffects.getInaccessibleMem()));
1691 newMemEffects |=
1692 llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
1693 convertModRefInfoToLLVM(memEffects.getOther()));
1694 newMemEffects |=
1695 llvm::MemoryEffects(llvm::MemoryEffects::Location::ErrnoMem,
1696 convertModRefInfoToLLVM(memEffects.getErrnoMem()));
1697 newMemEffects |=
1698 llvm::MemoryEffects(llvm::MemoryEffects::Location::TargetMem0,
1699 convertModRefInfoToLLVM(memEffects.getTargetMem0()));
1700 newMemEffects |=
1701 llvm::MemoryEffects(llvm::MemoryEffects::Location::TargetMem1,
1702 convertModRefInfoToLLVM(memEffects.getTargetMem1()));
1703 llvmFunc->setMemoryEffects(newMemEffects);
1704}
1705
1706llvm::Attribute
1708 if (!allocSizeAttr || allocSizeAttr.empty())
1709 return llvm::Attribute{};
1710
1711 unsigned elemSize = static_cast<unsigned>(allocSizeAttr[0]);
1712 std::optional<unsigned> numElems;
1713 if (allocSizeAttr.size() > 1)
1714 numElems = static_cast<unsigned>(allocSizeAttr[1]);
1715
1716 return llvm::Attribute::getWithAllocSizeArgs(getLLVMContext(), elemSize,
1717 numElems);
1718}
1720 llvm::AttrBuilder &Attrs) {
1721 std::optional<DenormalFPEnvAttr> denormalFpEnv = func.getDenormalFpenv();
1722 if (!denormalFpEnv)
1723 return;
1724
1725 llvm::DenormalMode DefaultMode(
1726 convertDenormalModeKindToLLVM(denormalFpEnv->getDefaultOutputMode()),
1727 convertDenormalModeKindToLLVM(denormalFpEnv->getDefaultInputMode()));
1728 llvm::DenormalMode FloatMode(
1729 convertDenormalModeKindToLLVM(denormalFpEnv->getFloatOutputMode()),
1730 convertDenormalModeKindToLLVM(denormalFpEnv->getFloatInputMode()));
1731
1732 llvm::DenormalFPEnv FPEnv(DefaultMode, FloatMode);
1733 Attrs.addDenormalFPEnvAttr(FPEnv);
1734}
1735
1736/// Converts function attributes from `func` and attaches them to `llvmFunc`.
1738 llvm::Function *llvmFunc) {
1739 // FIXME: Use AttrBuilder far all cases
1740 llvm::AttrBuilder AttrBuilder(llvmFunc->getContext());
1741
1742 if (func.getNoInlineAttr())
1743 llvmFunc->addFnAttr(llvm::Attribute::NoInline);
1744 if (func.getAlwaysInlineAttr())
1745 llvmFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1746 if (func.getInlineHintAttr())
1747 llvmFunc->addFnAttr(llvm::Attribute::InlineHint);
1748 if (func.getOptimizeNoneAttr())
1749 llvmFunc->addFnAttr(llvm::Attribute::OptimizeNone);
1750 if (func.getReturnsTwiceAttr())
1751 llvmFunc->addFnAttr(llvm::Attribute::ReturnsTwice);
1752 if (func.getColdAttr())
1753 llvmFunc->addFnAttr(llvm::Attribute::Cold);
1754 if (func.getHotAttr())
1755 llvmFunc->addFnAttr(llvm::Attribute::Hot);
1756 if (func.getNoduplicateAttr())
1757 llvmFunc->addFnAttr(llvm::Attribute::NoDuplicate);
1758 if (func.getConvergentAttr())
1759 llvmFunc->addFnAttr(llvm::Attribute::Convergent);
1760 if (func.getNoUnwindAttr())
1761 llvmFunc->addFnAttr(llvm::Attribute::NoUnwind);
1762 if (func.getWillReturnAttr())
1763 llvmFunc->addFnAttr(llvm::Attribute::WillReturn);
1764 if (func.getNoreturnAttr())
1765 llvmFunc->addFnAttr(llvm::Attribute::NoReturn);
1766 if (func.getOptsizeAttr())
1767 llvmFunc->addFnAttr(llvm::Attribute::OptimizeForSize);
1768 if (func.getMinsizeAttr())
1769 llvmFunc->addFnAttr(llvm::Attribute::MinSize);
1770 if (func.getSaveRegParamsAttr())
1771 llvmFunc->addFnAttr("save-reg-params");
1772 if (func.getNoCallerSavedRegistersAttr())
1773 llvmFunc->addFnAttr("no_caller_saved_registers");
1774 if (func.getNocallbackAttr())
1775 llvmFunc->addFnAttr(llvm::Attribute::NoCallback);
1776 if (StringAttr modFormat = func.getModularFormatAttr())
1777 llvmFunc->addFnAttr("modular-format", modFormat.getValue());
1778 if (TargetFeaturesAttr targetFeatAttr = func.getTargetFeaturesAttr())
1779 llvmFunc->addFnAttr("target-features", targetFeatAttr.getFeaturesString());
1780 if (FramePointerKindAttr fpAttr = func.getFramePointerAttr())
1781 llvmFunc->addFnAttr("frame-pointer", stringifyFramePointerKind(
1782 fpAttr.getFramePointerKind()));
1783 if (UWTableKindAttr uwTableKindAttr = func.getUwtableKindAttr())
1784 llvmFunc->setUWTableKind(
1785 convertUWTableKindToLLVM(uwTableKindAttr.getUwtableKind()));
1786 if (StringAttr zcsr = func.getZeroCallUsedRegsAttr())
1787 llvmFunc->addFnAttr("zero-call-used-regs", zcsr.getValue());
1788
1789 if (ArrayAttr noBuiltins = func.getNobuiltinsAttr()) {
1790 if (noBuiltins.empty())
1791 llvmFunc->addFnAttr("no-builtins");
1792
1793 mod.convertFunctionAttrCollection(noBuiltins, llvmFunc,
1795 }
1796
1797 mod.convertFunctionAttrCollection(func.getDefaultFuncAttrsAttr(), llvmFunc,
1799
1800 if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr());
1801 attr.isValid())
1802 llvmFunc->addFnAttr(attr);
1803
1805
1806 convertDenormalFPEnvAttribute(func, AttrBuilder);
1807 llvmFunc->addFnAttrs(AttrBuilder);
1808}
1809
1810/// Converts function attributes from `func` and attaches them to `llvmFunc`.
1812 llvm::Function *llvmFunc,
1813 ModuleTranslation &translation) {
1814 llvm::LLVMContext &llvmContext = llvmFunc->getContext();
1815
1816 if (VecTypeHintAttr vecTypeHint = func.getVecTypeHintAttr()) {
1817 Type type = vecTypeHint.getHint().getValue();
1818 llvm::Type *llvmType = translation.convertType(type);
1819 bool isSigned = vecTypeHint.getIsSigned();
1820 llvmFunc->setMetadata(
1821 func.getVecTypeHintAttrName(),
1822 convertVecTypeHintToMDNode(llvmContext, llvmType, isSigned));
1823 }
1824
1825 if (std::optional<ArrayRef<int32_t>> workGroupSizeHint =
1826 func.getWorkGroupSizeHint()) {
1827 llvmFunc->setMetadata(
1828 func.getWorkGroupSizeHintAttrName(),
1829 convertIntegerArrayToMDNode(llvmContext, *workGroupSizeHint));
1830 }
1831
1832 if (std::optional<ArrayRef<int32_t>> reqdWorkGroupSize =
1833 func.getReqdWorkGroupSize()) {
1834 llvmFunc->setMetadata(
1835 func.getReqdWorkGroupSizeAttrName(),
1836 convertIntegerArrayToMDNode(llvmContext, *reqdWorkGroupSize));
1837 }
1838
1839 if (std::optional<uint32_t> intelReqdSubGroupSize =
1840 func.getIntelReqdSubGroupSize()) {
1841 llvmFunc->setMetadata(
1842 func.getIntelReqdSubGroupSizeAttrName(),
1843 convertIntegerToMDNode(llvmContext,
1844 llvm::APInt(32, *intelReqdSubGroupSize)));
1845 }
1846}
1847
1848static LogicalResult convertParameterAttr(llvm::AttrBuilder &attrBuilder,
1849 llvm::Attribute::AttrKind llvmKind,
1850 NamedAttribute namedAttr,
1851 ModuleTranslation &moduleTranslation,
1852 Location loc) {
1854 .Case([&](TypeAttr typeAttr) {
1855 attrBuilder.addTypeAttr(
1856 llvmKind, moduleTranslation.convertType(typeAttr.getValue()));
1857 return success();
1858 })
1859 .Case([&](IntegerAttr intAttr) {
1860 attrBuilder.addRawIntAttr(llvmKind, intAttr.getInt());
1861 return success();
1862 })
1863 .Case([&](UnitAttr) {
1864 attrBuilder.addAttribute(llvmKind);
1865 return success();
1866 })
1867 .Case([&](LLVM::ConstantRangeAttr rangeAttr) {
1868 attrBuilder.addConstantRangeAttr(
1869 llvmKind,
1870 llvm::ConstantRange(rangeAttr.getLower(), rangeAttr.getUpper()));
1871 return success();
1872 })
1873 .Default([loc](auto) {
1874 return emitError(loc, "unsupported parameter attribute type");
1875 });
1876}
1877
1878FailureOr<llvm::AttrBuilder>
1879ModuleTranslation::convertParameterAttrs(LLVMFuncOp func, int argIdx,
1880 DictionaryAttr paramAttrs) {
1881 llvm::AttrBuilder attrBuilder(llvmModule->getContext());
1882 auto attrNameToKindMapping = getAttrNameToKindMapping();
1883 Location loc = func.getLoc();
1884
1885 for (auto namedAttr : paramAttrs) {
1886 auto it = attrNameToKindMapping.find(namedAttr.getName());
1887 if (it != attrNameToKindMapping.end()) {
1888 llvm::Attribute::AttrKind llvmKind = it->second;
1889 if (failed(convertParameterAttr(attrBuilder, llvmKind, namedAttr, *this,
1890 loc)))
1891 return failure();
1892 } else if (namedAttr.getNameDialect()) {
1893 if (failed(iface.convertParameterAttr(func, argIdx, namedAttr, *this)))
1894 return failure();
1895 }
1896 }
1897
1898 return attrBuilder;
1899}
1900
1902 ArgAndResultAttrsOpInterface attrsOp, llvm::CallBase *call,
1903 ArrayRef<unsigned> immArgPositions) {
1904 // Convert the argument attributes.
1905 if (ArrayAttr argAttrsArray = attrsOp.getArgAttrsAttr()) {
1906 unsigned argAttrIdx = 0;
1907 llvm::SmallDenseSet<unsigned> immArgPositionsSet(immArgPositions.begin(),
1908 immArgPositions.end());
1909 for (unsigned argIdx : llvm::seq<unsigned>(call->arg_size())) {
1910 if (argAttrIdx >= argAttrsArray.size())
1911 break;
1912 // Skip immediate arguments (they have no entries in argAttrsArray).
1913 if (immArgPositionsSet.contains(argIdx))
1914 continue;
1915 // Skip empty argument attributes.
1916 auto argAttrs = cast<DictionaryAttr>(argAttrsArray[argAttrIdx++]);
1917 if (argAttrs.empty())
1918 continue;
1919 // Convert and add attributes to the call instruction.
1920 FailureOr<llvm::AttrBuilder> attrBuilder =
1921 convertParameterAttrs(attrsOp->getLoc(), argAttrs);
1922 if (failed(attrBuilder))
1923 return failure();
1924 call->addParamAttrs(argIdx, *attrBuilder);
1925 }
1926 }
1927
1928 // Convert the result attributes.
1929 if (ArrayAttr resAttrsArray = attrsOp.getResAttrsAttr()) {
1930 if (!resAttrsArray.empty()) {
1931 auto resAttrs = cast<DictionaryAttr>(resAttrsArray[0]);
1932 FailureOr<llvm::AttrBuilder> attrBuilder =
1933 convertParameterAttrs(attrsOp->getLoc(), resAttrs);
1934 if (failed(attrBuilder))
1935 return failure();
1936 call->addRetAttrs(*attrBuilder);
1937 }
1938 }
1939
1940 return success();
1941}
1942
1943std::optional<llvm::Attribute>
1945 if (auto str = dyn_cast<StringAttr>(a))
1946 return llvm::Attribute::get(ctx, ("no-builtin-" + str.getValue()).str());
1947 return std::nullopt;
1948}
1949
1950std::optional<llvm::Attribute>
1952 mlir::NamedAttribute namedAttr) {
1953 StringAttr name = namedAttr.getName();
1954 Attribute value = namedAttr.getValue();
1955
1956 if (auto strVal = dyn_cast<StringAttr>(value))
1957 return llvm::Attribute::get(ctx, name.getValue(), strVal.getValue());
1958 if (mlir::isa<UnitAttr>(value))
1959 return llvm::Attribute::get(ctx, name.getValue());
1960 return std::nullopt;
1961}
1962
1963FailureOr<llvm::AttrBuilder>
1964ModuleTranslation::convertParameterAttrs(Location loc,
1965 DictionaryAttr paramAttrs) {
1966 llvm::AttrBuilder attrBuilder(llvmModule->getContext());
1967 auto attrNameToKindMapping = getAttrNameToKindMapping();
1968
1969 for (auto namedAttr : paramAttrs) {
1970 auto it = attrNameToKindMapping.find(namedAttr.getName());
1971 if (it != attrNameToKindMapping.end()) {
1972 llvm::Attribute::AttrKind llvmKind = it->second;
1973 if (failed(convertParameterAttr(attrBuilder, llvmKind, namedAttr, *this,
1974 loc)))
1975 return failure();
1976 }
1977 }
1978
1979 return attrBuilder;
1980}
1981
1982LogicalResult ModuleTranslation::convertFunctionSignatures() {
1983 // Declare all functions first because there may be function calls that form a
1984 // call graph with cycles, or global initializers that reference functions.
1985 for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
1986 llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction(
1987 function.getName(),
1988 cast<llvm::FunctionType>(convertType(function.getFunctionType())));
1989 llvm::Function *llvmFunc = cast<llvm::Function>(llvmFuncCst.getCallee());
1990 llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
1991 llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
1992 mapFunction(function.getName(), llvmFunc);
1993 addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
1994
1995 // Convert function attributes.
1996 convertFunctionAttributes(*this, function, llvmFunc);
1997
1998 // Convert function kernel attributes to metadata.
1999 convertFunctionKernelAttributes(function, llvmFunc, *this);
2000
2001 // Convert function_entry_count attribute to metadata.
2002 if (std::optional<uint64_t> entryCount = function.getFunctionEntryCount())
2003 llvmFunc->setEntryCount(entryCount.value());
2004
2005 // Convert result attributes.
2006 if (ArrayAttr allResultAttrs = function.getAllResultAttrs()) {
2007 DictionaryAttr resultAttrs = cast<DictionaryAttr>(allResultAttrs[0]);
2008 FailureOr<llvm::AttrBuilder> attrBuilder =
2009 convertParameterAttrs(function, -1, resultAttrs);
2010 if (failed(attrBuilder))
2011 return failure();
2012 llvmFunc->addRetAttrs(*attrBuilder);
2013 }
2014
2015 // Convert argument attributes.
2016 for (auto [argIdx, llvmArg] : llvm::enumerate(llvmFunc->args())) {
2017 if (DictionaryAttr argAttrs = function.getArgAttrDict(argIdx)) {
2018 FailureOr<llvm::AttrBuilder> attrBuilder =
2019 convertParameterAttrs(function, argIdx, argAttrs);
2020 if (failed(attrBuilder))
2021 return failure();
2022 llvmArg.addAttrs(*attrBuilder);
2023 }
2024 }
2025
2026 // Forward the pass-through attributes to LLVM.
2027 FailureOr<llvm::AttrBuilder> convertedPassthroughAttrs =
2028 convertMLIRAttributesToLLVM(function.getLoc(), llvmFunc->getContext(),
2029 function.getPassthroughAttr(),
2030 function.getPassthroughAttrName());
2031 if (failed(convertedPassthroughAttrs))
2032 return failure();
2033 llvmFunc->addFnAttrs(*convertedPassthroughAttrs);
2034
2035 // Convert visibility attribute.
2036 llvmFunc->setVisibility(convertVisibilityToLLVM(function.getVisibility_()));
2037
2038 // Convert the comdat attribute.
2039 if (std::optional<mlir::SymbolRefAttr> comdat = function.getComdat()) {
2040 auto selectorOp = cast<ComdatSelectorOp>(
2041 SymbolTable::lookupNearestSymbolFrom(function, *comdat));
2042 llvmFunc->setComdat(comdatMapping.lookup(selectorOp));
2043 }
2044
2045 if (auto gc = function.getGarbageCollector())
2046 llvmFunc->setGC(gc->str());
2047
2048 if (auto unnamedAddr = function.getUnnamedAddr())
2049 llvmFunc->setUnnamedAddr(convertUnnamedAddrToLLVM(*unnamedAddr));
2050
2051 if (auto alignment = function.getAlignment())
2052 llvmFunc->setAlignment(llvm::MaybeAlign(*alignment));
2053
2054 // Translate the debug information for this function.
2055 debugTranslation->translate(function, *llvmFunc);
2056 }
2057
2058 return success();
2059}
2060
2061LogicalResult ModuleTranslation::convertFunctions() {
2062 // Convert functions.
2063 for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
2064 // Do not convert external functions, but do process dialect attributes
2065 // attached to them.
2066 if (function.isExternal()) {
2067 if (failed(convertDialectAttributes(function, {})))
2068 return failure();
2069 continue;
2070 }
2071
2072 if (failed(convertOneFunction(function)))
2073 return failure();
2074 }
2075
2076 return success();
2077}
2078
2079LogicalResult ModuleTranslation::convertIFuncs() {
2080 for (auto op : getModuleBody(mlirModule).getOps<IFuncOp>()) {
2081 llvm::Type *type = convertType(op.getIFuncType());
2082 llvm::GlobalValue::LinkageTypes linkage =
2083 convertLinkageToLLVM(op.getLinkage());
2084 llvm::Constant *resolver;
2085 if (auto *resolverFn = lookupFunction(op.getResolver())) {
2086 resolver = cast<llvm::Constant>(resolverFn);
2087 } else {
2088 Operation *aliasOp = symbolTable().lookupSymbolIn(parentLLVMModule(op),
2089 op.getResolverAttr());
2090 resolver = cast<llvm::Constant>(lookupAlias(aliasOp));
2091 }
2092
2093 auto *ifunc =
2094 llvm::GlobalIFunc::create(type, op.getAddressSpace(), linkage,
2095 op.getSymName(), resolver, llvmModule.get());
2096 addRuntimePreemptionSpecifier(op.getDsoLocal(), ifunc);
2097 ifunc->setUnnamedAddr(convertUnnamedAddrToLLVM(op.getUnnamedAddr()));
2098 ifunc->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
2099
2100 ifuncMapping.try_emplace(op, ifunc);
2101 }
2102
2103 return success();
2104}
2105
2106LogicalResult ModuleTranslation::convertComdats() {
2107 for (auto comdatOp : getModuleBody(mlirModule).getOps<ComdatOp>()) {
2108 for (auto selectorOp : comdatOp.getOps<ComdatSelectorOp>()) {
2109 llvm::Module *module = getLLVMModule();
2110 if (module->getComdatSymbolTable().contains(selectorOp.getSymName()))
2111 return emitError(selectorOp.getLoc())
2112 << "comdat selection symbols must be unique even in different "
2113 "comdat regions";
2114 llvm::Comdat *comdat = module->getOrInsertComdat(selectorOp.getSymName());
2115 comdat->setSelectionKind(convertComdatToLLVM(selectorOp.getComdat()));
2116 comdatMapping.try_emplace(selectorOp, comdat);
2117 }
2118 }
2119 return success();
2120}
2121
2122LogicalResult ModuleTranslation::convertUnresolvedBlockAddress() {
2123 for (auto &[blockAddressOp, llvmCst] : unresolvedBlockAddressMapping) {
2124 BlockAddressAttr blockAddressAttr = blockAddressOp.getBlockAddr();
2125 llvm::BasicBlock *llvmBlock = lookupBlockAddress(blockAddressAttr);
2126 assert(llvmBlock && "expected LLVM blocks to be already translated");
2127
2128 // Update mapping with new block address constant.
2129 auto *llvmBlockAddr = llvm::BlockAddress::get(
2130 lookupFunction(blockAddressAttr.getFunction().getValue()), llvmBlock);
2131 llvmCst->replaceAllUsesWith(llvmBlockAddr);
2132 assert(llvmCst->use_empty() && "expected all uses to be replaced");
2133 cast<llvm::GlobalVariable>(llvmCst)->eraseFromParent();
2134 }
2135 unresolvedBlockAddressMapping.clear();
2136 return success();
2137}
2138
2139void ModuleTranslation::setAccessGroupsMetadata(AccessGroupOpInterface op,
2140 llvm::Instruction *inst) {
2141 if (llvm::MDNode *node = loopAnnotationTranslation->getAccessGroups(op))
2142 inst->setMetadata(llvm::LLVMContext::MD_access_group, node);
2143}
2144
2145llvm::MDNode *
2146ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
2147 auto [scopeIt, scopeInserted] =
2148 aliasScopeMetadataMapping.try_emplace(aliasScopeAttr, nullptr);
2149 if (!scopeInserted)
2150 return scopeIt->second;
2151 llvm::LLVMContext &ctx = llvmModule->getContext();
2152 auto dummy = llvm::MDNode::getTemporary(ctx, {});
2153 // Convert the domain metadata node if necessary.
2154 auto [domainIt, insertedDomain] = aliasDomainMetadataMapping.try_emplace(
2155 aliasScopeAttr.getDomain(), nullptr);
2156 if (insertedDomain) {
2158 // Placeholder for potential self-reference.
2159 operands.push_back(dummy.get());
2160 if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
2161 operands.push_back(llvm::MDString::get(ctx, description));
2162 domainIt->second = llvm::MDNode::get(ctx, operands);
2163 // Self-reference for uniqueness.
2164 llvm::Metadata *replacement;
2165 if (auto stringAttr =
2166 dyn_cast<StringAttr>(aliasScopeAttr.getDomain().getId()))
2167 replacement = llvm::MDString::get(ctx, stringAttr.getValue());
2168 else
2169 replacement = domainIt->second;
2170 domainIt->second->replaceOperandWith(0, replacement);
2171 }
2172 // Convert the scope metadata node.
2173 assert(domainIt->second && "Scope's domain should already be valid");
2175 // Placeholder for potential self-reference.
2176 operands.push_back(dummy.get());
2177 operands.push_back(domainIt->second);
2178 if (StringAttr description = aliasScopeAttr.getDescription())
2179 operands.push_back(llvm::MDString::get(ctx, description));
2180 scopeIt->second = llvm::MDNode::get(ctx, operands);
2181 // Self-reference for uniqueness.
2182 llvm::Metadata *replacement;
2183 if (auto stringAttr = dyn_cast<StringAttr>(aliasScopeAttr.getId()))
2184 replacement = llvm::MDString::get(ctx, stringAttr.getValue());
2185 else
2186 replacement = scopeIt->second;
2187 scopeIt->second->replaceOperandWith(0, replacement);
2188 return scopeIt->second;
2189}
2190
2192 ArrayRef<AliasScopeAttr> aliasScopeAttrs) {
2194 nodes.reserve(aliasScopeAttrs.size());
2195 for (AliasScopeAttr aliasScopeAttr : aliasScopeAttrs)
2196 nodes.push_back(getOrCreateAliasScope(aliasScopeAttr));
2197 return llvm::MDNode::get(getLLVMContext(), nodes);
2198}
2199
2200void ModuleTranslation::setAliasScopeMetadata(AliasAnalysisOpInterface op,
2201 llvm::Instruction *inst) {
2202 auto populateScopeMetadata = [&](ArrayAttr aliasScopeAttrs, unsigned kind) {
2203 if (!aliasScopeAttrs || aliasScopeAttrs.empty())
2204 return;
2205 llvm::MDNode *node = getOrCreateAliasScopes(
2206 llvm::to_vector(aliasScopeAttrs.getAsRange<AliasScopeAttr>()));
2207 inst->setMetadata(kind, node);
2208 };
2209
2210 populateScopeMetadata(op.getAliasScopesOrNull(),
2211 llvm::LLVMContext::MD_alias_scope);
2212 populateScopeMetadata(op.getNoAliasScopesOrNull(),
2213 llvm::LLVMContext::MD_noalias);
2214}
2215
2216llvm::MDNode *ModuleTranslation::getTBAANode(TBAATagAttr tbaaAttr) const {
2217 return tbaaMetadataMapping.lookup(tbaaAttr);
2218}
2219
2220void ModuleTranslation::setTBAAMetadata(AliasAnalysisOpInterface op,
2221 llvm::Instruction *inst) {
2222 ArrayAttr tagRefs = op.getTBAATagsOrNull();
2223 if (!tagRefs || tagRefs.empty())
2224 return;
2225
2226 // LLVM IR currently does not support attaching more than one TBAA access tag
2227 // to a memory accessing instruction. It may be useful to support this in
2228 // future, but for the time being just ignore the metadata if MLIR operation
2229 // has multiple access tags.
2230 if (tagRefs.size() > 1) {
2231 op.emitWarning() << "TBAA access tags were not translated, because LLVM "
2232 "IR only supports a single tag per instruction";
2233 return;
2234 }
2235
2236 llvm::MDNode *node = getTBAANode(cast<TBAATagAttr>(tagRefs[0]));
2237 inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
2238}
2239
2241 DereferenceableOpInterface op, llvm::Instruction *inst) {
2242 DereferenceableAttr derefAttr = op.getDereferenceableOrNull();
2243 if (!derefAttr)
2244 return;
2245
2246 llvm::MDNode *derefSizeNode = llvm::MDNode::get(
2248 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
2249 llvm::IntegerType::get(getLLVMContext(), 64), derefAttr.getBytes())));
2250 unsigned kindId = derefAttr.getMayBeNull()
2251 ? llvm::LLVMContext::MD_dereferenceable_or_null
2252 : llvm::LLVMContext::MD_dereferenceable;
2253 inst->setMetadata(kindId, derefSizeNode);
2254}
2255
2256void ModuleTranslation::setBranchWeightsMetadata(WeightedBranchOpInterface op) {
2257 SmallVector<uint32_t> weights;
2258 llvm::transform(op.getWeights(), std::back_inserter(weights),
2259 [](int32_t value) { return static_cast<uint32_t>(value); });
2260 if (weights.empty())
2261 return;
2262
2263 llvm::Instruction *inst = isa<CallOp>(op) ? lookupCall(op) : lookupBranch(op);
2264 assert(inst && "expected the operation to have a mapping to an instruction");
2265 inst->setMetadata(
2266 llvm::LLVMContext::MD_prof,
2267 llvm::MDBuilder(getLLVMContext()).createBranchWeights(weights));
2268}
2269
2270LogicalResult ModuleTranslation::createTBAAMetadata() {
2271 llvm::LLVMContext &ctx = llvmModule->getContext();
2272 llvm::IntegerType *offsetTy = llvm::IntegerType::get(ctx, 64);
2273
2274 // Walk the entire module and create all metadata nodes for the TBAA
2275 // attributes. The code below relies on two invariants of the
2276 // `AttrTypeWalker`:
2277 // 1. Attributes are visited in post-order: Since the attributes create a DAG,
2278 // this ensures that any lookups into `tbaaMetadataMapping` for child
2279 // attributes succeed.
2280 // 2. Attributes are only ever visited once: This way we don't leak any
2281 // LLVM metadata instances.
2282 AttrTypeWalker walker;
2283 walker.addWalk([&](TBAARootAttr root) {
2284 llvm::MDNode *node;
2285 if (StringAttr id = root.getId()) {
2286 node = llvm::MDNode::get(ctx, llvm::MDString::get(ctx, id));
2287 } else {
2288 // Anonymous root nodes are self-referencing.
2289 auto selfRef = llvm::MDNode::getTemporary(ctx, {});
2290 node = llvm::MDNode::get(ctx, {selfRef.get()});
2291 node->replaceOperandWith(0, node);
2292 }
2293 tbaaMetadataMapping.insert({root, node});
2294 });
2295
2296 walker.addWalk([&](TBAATypeDescriptorAttr descriptor) {
2297 SmallVector<llvm::Metadata *> operands;
2298 operands.push_back(llvm::MDString::get(ctx, descriptor.getId()));
2299 for (TBAAMemberAttr member : descriptor.getMembers()) {
2300 operands.push_back(tbaaMetadataMapping.lookup(member.getTypeDesc()));
2301 operands.push_back(llvm::ConstantAsMetadata::get(
2302 llvm::ConstantInt::get(offsetTy, member.getOffset())));
2303 }
2304
2305 tbaaMetadataMapping.insert({descriptor, llvm::MDNode::get(ctx, operands)});
2306 });
2307
2308 walker.addWalk([&](TBAATagAttr tag) {
2309 SmallVector<llvm::Metadata *> operands;
2310
2311 operands.push_back(tbaaMetadataMapping.lookup(tag.getBaseType()));
2312 operands.push_back(tbaaMetadataMapping.lookup(tag.getAccessType()));
2313
2314 operands.push_back(llvm::ConstantAsMetadata::get(
2315 llvm::ConstantInt::get(offsetTy, tag.getOffset())));
2316 if (tag.getConstant())
2317 operands.push_back(
2318 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(offsetTy, 1)));
2319
2320 tbaaMetadataMapping.insert({tag, llvm::MDNode::get(ctx, operands)});
2321 });
2322
2323 mlirModule->walk([&](AliasAnalysisOpInterface analysisOpInterface) {
2324 if (auto attr = analysisOpInterface.getTBAATagsOrNull())
2325 walker.walk(attr);
2326 });
2327
2328 return success();
2329}
2330
2331LogicalResult ModuleTranslation::createIdentMetadata() {
2332 if (auto attr = mlirModule->getAttrOfType<StringAttr>(
2333 LLVMDialect::getIdentAttrName())) {
2334 StringRef ident = attr;
2335 llvm::LLVMContext &ctx = llvmModule->getContext();
2336 llvm::NamedMDNode *namedMd =
2337 llvmModule->getOrInsertNamedMetadata(LLVMDialect::getIdentAttrName());
2338 llvm::MDNode *md = llvm::MDNode::get(ctx, llvm::MDString::get(ctx, ident));
2339 namedMd->addOperand(md);
2340 }
2341
2342 return success();
2343}
2344
2345LogicalResult ModuleTranslation::createCommandlineMetadata() {
2346 if (auto attr = mlirModule->getAttrOfType<StringAttr>(
2347 LLVMDialect::getCommandlineAttrName())) {
2348 StringRef cmdLine = attr;
2349 llvm::LLVMContext &ctx = llvmModule->getContext();
2350 llvm::NamedMDNode *nmd = llvmModule->getOrInsertNamedMetadata(
2351 LLVMDialect::getCommandlineAttrName());
2352 llvm::MDNode *md =
2353 llvm::MDNode::get(ctx, llvm::MDString::get(ctx, cmdLine));
2354 nmd->addOperand(md);
2355 }
2356
2357 return success();
2358}
2359
2360LogicalResult ModuleTranslation::createDependentLibrariesMetadata() {
2361 if (auto dependentLibrariesAttr = mlirModule->getDiscardableAttr(
2362 LLVM::LLVMDialect::getDependentLibrariesAttrName())) {
2363 auto *nmd =
2364 llvmModule->getOrInsertNamedMetadata("llvm.dependent-libraries");
2365 llvm::LLVMContext &ctx = llvmModule->getContext();
2366 for (auto libAttr :
2367 cast<ArrayAttr>(dependentLibrariesAttr).getAsRange<StringAttr>()) {
2368 auto *md =
2369 llvm::MDNode::get(ctx, llvm::MDString::get(ctx, libAttr.getValue()));
2370 nmd->addOperand(md);
2371 }
2372 }
2373 return success();
2374}
2375
2377 llvm::Instruction *inst) {
2378 LoopAnnotationAttr attr =
2380 .Case<LLVM::BrOp, LLVM::CondBrOp>(
2381 [](auto branchOp) { return branchOp.getLoopAnnotationAttr(); });
2382 if (!attr)
2383 return;
2384 llvm::MDNode *loopMD =
2385 loopAnnotationTranslation->translateLoopAnnotation(attr, op);
2386 inst->setMetadata(llvm::LLVMContext::MD_loop, loopMD);
2387}
2388
2389void ModuleTranslation::setDisjointFlag(Operation *op, llvm::Value *value) {
2390 auto iface = cast<DisjointFlagInterface>(op);
2391 // We do a dyn_cast here in case the value got folded into a constant.
2392 if (auto *disjointInst = dyn_cast<llvm::PossiblyDisjointInst>(value))
2393 disjointInst->setIsDisjoint(iface.getIsDisjoint());
2394}
2395
2397 return typeTranslator.translateType(type);
2398}
2399
2400/// A helper to look up remapped operands in the value remapping table.
2403 remapped.reserve(values.size());
2404 for (Value v : values)
2405 remapped.push_back(lookupValue(v));
2406 return remapped;
2407}
2408
2409llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
2410 if (!ompBuilder) {
2411 ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
2412
2413 // Flags represented as top-level OpenMP dialect attributes are set in
2414 // `OpenMPDialectLLVMIRTranslationInterface::amendOperation()`. Here we set
2415 // the default configuration.
2416 llvm::OpenMPIRBuilderConfig config(
2417 /* IsTargetDevice = */ false, /* IsGPU = */ false,
2418 /* OpenMPOffloadMandatory = */ false,
2419 /* HasRequiresReverseOffload = */ false,
2420 /* HasRequiresUnifiedAddress = */ false,
2421 /* HasRequiresUnifiedSharedMemory = */ false,
2422 /* HasRequiresDynamicAllocators = */ false);
2423 unsigned int defaultAS =
2424 llvmModule->getDataLayout().getProgramAddressSpace();
2425 config.setDefaultTargetAS(defaultAS);
2426 config.setRuntimeCC(llvmModule->getTargetTriple().isSPIRV()
2427 ? llvm::CallingConv::SPIR_FUNC
2428 : llvm::CallingConv::C);
2429 ompBuilder->setConfig(std::move(config));
2430 ompBuilder->initialize();
2431 }
2432 return ompBuilder.get();
2433}
2434
2435llvm::vfs::FileSystem &ModuleTranslation::getFileSystem() {
2436 if (fileSystem)
2437 return *fileSystem;
2438 return *llvm::vfs::getRealFileSystem();
2439}
2440
2442 llvm::DILocalScope *scope) {
2443 return debugTranslation->translateLoc(loc, scope);
2444}
2445
2446llvm::DIExpression *
2447ModuleTranslation::translateExpression(LLVM::DIExpressionAttr attr) {
2448 return debugTranslation->translateExpression(attr);
2449}
2450
2451llvm::DIGlobalVariableExpression *
2453 LLVM::DIGlobalVariableExpressionAttr attr) {
2454 return debugTranslation->translateGlobalVariableExpression(attr);
2455}
2456
2458 return debugTranslation->translate(attr);
2459}
2460
2461llvm::RoundingMode
2462ModuleTranslation::translateRoundingMode(LLVM::RoundingMode rounding) {
2463 return convertRoundingModeToLLVM(rounding);
2464}
2465
2467 LLVM::FPExceptionBehavior exceptionBehavior) {
2468 return convertFPExceptionBehaviorToLLVM(exceptionBehavior);
2469}
2470
2471llvm::NamedMDNode *
2473 return llvmModule->getOrInsertNamedMetadata(name);
2474}
2475
2476static std::unique_ptr<llvm::Module>
2477prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
2478 StringRef name) {
2479 m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
2480 auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
2481 if (auto dataLayoutAttr =
2482 m->getDiscardableAttr(LLVM::LLVMDialect::getDataLayoutAttrName())) {
2483 llvmModule->setDataLayout(cast<StringAttr>(dataLayoutAttr).getValue());
2484 } else {
2485 FailureOr<llvm::DataLayout> llvmDataLayout(llvm::DataLayout(""));
2486 if (auto iface = dyn_cast<DataLayoutOpInterface>(m)) {
2487 if (DataLayoutSpecInterface spec = iface.getDataLayoutSpec()) {
2488 llvmDataLayout =
2489 translateDataLayout(spec, DataLayout(iface), m->getLoc());
2490 }
2491 } else if (auto mod = dyn_cast<ModuleOp>(m)) {
2492 if (DataLayoutSpecInterface spec = mod.getDataLayoutSpec()) {
2493 llvmDataLayout =
2494 translateDataLayout(spec, DataLayout(mod), m->getLoc());
2495 }
2496 }
2497 if (failed(llvmDataLayout))
2498 return nullptr;
2499 llvmModule->setDataLayout(*llvmDataLayout);
2500 }
2501 if (auto targetTripleAttr =
2502 m->getDiscardableAttr(LLVM::LLVMDialect::getTargetTripleAttrName()))
2503 llvmModule->setTargetTriple(
2504 llvm::Triple(cast<StringAttr>(targetTripleAttr).getValue()));
2505
2506 if (auto asmAttr = m->getDiscardableAttr(
2507 LLVM::LLVMDialect::getModuleLevelAsmAttrName())) {
2508 auto asmArrayAttr = dyn_cast<ArrayAttr>(asmAttr);
2509 if (!asmArrayAttr) {
2510 m->emitError("expected an array attribute for a module level asm");
2511 return nullptr;
2512 }
2513
2514 for (Attribute elt : asmArrayAttr) {
2515 auto asmStrAttr = dyn_cast<StringAttr>(elt);
2516 if (!asmStrAttr) {
2517 m->emitError(
2518 "expected a string attribute for each entry of a module level asm");
2519 return nullptr;
2520 }
2521 llvmModule->appendModuleInlineAsm(asmStrAttr.getValue());
2522 }
2523 }
2524
2525 return llvmModule;
2526}
2527
2528std::unique_ptr<llvm::Module>
2529mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
2530 StringRef name, bool disableVerification,
2531 llvm::vfs::FileSystem *fs) {
2532 if (!satisfiesLLVMModule(module)) {
2533 module->emitOpError("can not be translated to an LLVMIR module");
2534 return nullptr;
2535 }
2536
2537 std::unique_ptr<llvm::Module> llvmModule =
2538 prepareLLVMModule(module, llvmContext, name);
2539 if (!llvmModule)
2540 return nullptr;
2541
2544
2545 ModuleTranslation translator(module, std::move(llvmModule), fs);
2546 llvm::IRBuilder<llvm::TargetFolder> llvmBuilder(
2547 llvmContext,
2548 llvm::TargetFolder(translator.getLLVMModule()->getDataLayout()));
2549
2550 // Convert module before functions and operations inside, so dialect
2551 // attributes can be used to change dialect-specific global configurations via
2552 // `amendOperation()`. These configurations can then influence the translation
2553 // of operations afterwards.
2554 if (failed(translator.convertOperation(*module, llvmBuilder)))
2555 return nullptr;
2556
2557 if (failed(translator.convertComdats()))
2558 return nullptr;
2559 if (failed(translator.convertFunctionSignatures()))
2560 return nullptr;
2561 if (failed(translator.convertGlobalsAndAliases()))
2562 return nullptr;
2563 if (failed(translator.convertIFuncs()))
2564 return nullptr;
2565 if (failed(translator.createTBAAMetadata()))
2566 return nullptr;
2567 if (failed(translator.createIdentMetadata()))
2568 return nullptr;
2569 if (failed(translator.createCommandlineMetadata()))
2570 return nullptr;
2571 if (failed(translator.createDependentLibrariesMetadata()))
2572 return nullptr;
2573
2574 // Convert other top-level operations if possible.
2575 for (Operation &o : getModuleBody(module).getOperations()) {
2576 if (!isa<LLVM::LLVMFuncOp, LLVM::AliasOp, LLVM::GlobalOp,
2577 LLVM::GlobalCtorsOp, LLVM::GlobalDtorsOp, LLVM::ComdatOp,
2578 LLVM::IFuncOp>(&o) &&
2579 !o.hasTrait<OpTrait::IsTerminator>() &&
2580 failed(translator.convertOperation(o, llvmBuilder))) {
2581 return nullptr;
2582 }
2583 }
2584
2585 // Operations in function bodies with symbolic references must be converted
2586 // after the top-level operations they refer to are declared, so we do it
2587 // last.
2588 if (failed(translator.convertFunctions()))
2589 return nullptr;
2590
2591 // Now that all MLIR blocks are resolved into LLVM ones, patch block address
2592 // constants to point to the correct blocks.
2593 if (failed(translator.convertUnresolvedBlockAddress()))
2594 return nullptr;
2595
2596 // Add the necessary debug info module flags, if they were not encoded in MLIR
2597 // beforehand.
2598 translator.debugTranslation->addModuleFlagsIfNotPresent();
2599
2600 // Call the OpenMP IR Builder callbacks prior to verifying the module
2601 if (auto *ompBuilder = translator.getOpenMPBuilder())
2602 ompBuilder->finalize();
2603
2604 if (!disableVerification &&
2605 llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
2606 return nullptr;
2607
2608 return std::move(translator.llvmModule);
2609}
return success()
ArrayAttr()
b getContext())
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static Value getPHISourceValue(Block *current, Block *pred, unsigned numArguments, unsigned index)
Get the SSA value passed to the current block from the terminator operation of its predecessor.
static llvm::Type * getInnermostElementType(llvm::Type *type)
Returns the first non-sequential type nested in sequential types.
static void addRuntimePreemptionSpecifier(bool dsoLocalRequested, llvm::GlobalValue *gv)
Sets the runtime preemption specifier of gv to dso_local if dsoLocalRequested is true,...
static Block & getModuleBody(Operation *module)
A helper method to get the single Block in an operation honoring LLVM's module requirements.
static llvm::MDNode * convertIntegerArrayToMDNode(llvm::LLVMContext &context, ArrayRef< int32_t > values)
Return an MDNode with a tuple given by the values in values.
static void convertDenormalFPEnvAttribute(LLVMFuncOp func, llvm::AttrBuilder &Attrs)
static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage, llvm::Constant *cst)
A helper method to decide if a constant must not be set as a global variable initializer.
static llvm::MDNode * convertIntegerToMDNode(llvm::LLVMContext &context, const llvm::APInt &value)
Return a representation of value as an MDNode.
static llvm::Metadata * convertIntegerToMetadata(llvm::LLVMContext &context, const llvm::APInt &value)
Return a representation of value as metadata.
static FailureOr< llvm::Attribute > convertMLIRAttributeToLLVM(Location loc, llvm::LLVMContext &ctx, StringRef key, StringRef value=StringRef())
Attempts to translate an MLIR attribute identified by key, optionally with the given value,...
static void convertFunctionKernelAttributes(LLVMFuncOp func, llvm::Function *llvmFunc, ModuleTranslation &translation)
Converts function attributes from func and attaches them to llvmFunc.
static LogicalResult convertParameterAttr(llvm::AttrBuilder &attrBuilder, llvm::Attribute::AttrKind llvmKind, NamedAttribute namedAttr, ModuleTranslation &moduleTranslation, Location loc)
static llvm::Constant * buildSequentialConstant(ArrayRef< llvm::Constant * > &constants, ArrayRef< int64_t > shape, llvm::Type *type, Location loc)
Builds a constant of a sequential LLVM type type, potentially containing other sequential types recur...
static FailureOr< llvm::AttrBuilder > convertMLIRAttributesToLLVM(Location loc, llvm::LLVMContext &ctx, ArrayAttr arrayAttr, StringRef arrayAttrName)
Converts the MLIR attributes listed in the given array attribute into LLVM attributes.
static void convertFunctionMemoryAttributes(LLVMFuncOp func, llvm::Function *llvmFunc)
Converts memory effect attributes from func and attaches them to llvmFunc.
static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func, llvm::Function *llvmFunc)
Converts function attributes from func and attaches them to llvmFunc.
static llvm::Constant * convertDenseResourceElementsAttr(Location loc, DenseResourceElementsAttr denseResourceAttr, llvm::Type *llvmType, const ModuleTranslation &moduleTranslation)
Convert a dense resource elements attribute to an LLVM IR constant using its raw data storage if poss...
static llvm::MDNode * convertVecTypeHintToMDNode(llvm::LLVMContext &context, llvm::Type *type, bool isSigned)
Return an MDNode encoding vec_type_hint metadata.
static llvm::Constant * convertDenseElementsAttr(Location loc, DenseElementsAttr denseElementsAttr, llvm::Type *llvmType, const ModuleTranslation &moduleTranslation)
Convert a dense elements attribute to an LLVM IR constant using its raw data storage if possible.
static std::unique_ptr< llvm::Module > prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext, StringRef name)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Definition Traits.cpp:117
This class represents a processed binary blob of data.
Definition AsmState.h:91
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Definition AsmState.h:145
void addWalk(WalkFn< Attribute > &&fn)
Register a walk function for a given attribute or type.
WalkResult walk(T element)
Walk the given attribute/type, and recursively walk any sub elements.
Attributes are known-constant values of operations.
Definition Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Block represents an ordered list of Operations.
Definition Block.h:33
iterator_range< pred_iterator > getPredecessors()
Definition Block.h:250
Operation & front()
Definition Block.h:163
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
BlockArgListType getArguments()
Definition Block.h:97
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
Definition Block.h:222
The main mechanism for performing data layout queries.
std::optional< uint64_t > getTypeIndexBitwidth(Type t) const
Returns the bitwidth that should be used when performing index computations for the given pointer-lik...
uint64_t getTypePreferredAlignment(Type t) const
Returns the preferred of the given type in the current scope.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
An attribute that represents a reference to a dense vector or tensor object.
int64_t getNumElements() const
Returns the number of elements held by this attribute.
std::enable_if_t<!std::is_base_of< Attribute, T >::value||std::is_same< Attribute, T >::value, T > getSplatValue() const
Return the splat value for this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
const InterfaceType * getInterfaceFor(Object *obj) const
Get the interface for a given object, or null if one is not registered.
This class represents the base attribute for all debug info attributes.
Definition LLVMAttrs.h:29
Implementation class for module translation.
llvm::fp::ExceptionBehavior translateFPExceptionBehavior(LLVM::FPExceptionBehavior exceptionBehavior)
Translates the given LLVM FP exception behavior metadata.
llvm::CallInst * lookupCall(Operation *op) const
Finds an LLVM call instruction that corresponds to the given MLIR call operation.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
llvm::DIGlobalVariableExpression * translateGlobalVariableExpression(LLVM::DIGlobalVariableExpressionAttr attr)
Translates the given LLVM global variable expression metadata.
llvm::Attribute convertAllocsizeAttr(DenseI32ArrayAttr allocsizeAttr)
llvm::NamedMDNode * getOrInsertNamedModuleMetadata(StringRef name)
Gets the named metadata in the LLVM IR module being constructed, creating it if it does not exist.
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
void mapFunction(StringRef name, llvm::Function *func)
Stores the mapping between a function name and its LLVM IR representation.
void convertFunctionAttrCollection(AttrsTy attrs, Operation *op, const Converter &conv)
A template that takes a collection-like attribute, and converts it via a user provided callback,...
llvm::DILocation * translateLoc(Location loc, llvm::DILocalScope *scope)
Translates the given location.
void setDereferenceableMetadata(DereferenceableOpInterface op, llvm::Instruction *inst)
Sets LLVM dereferenceable metadata for operations that have dereferenceable attributes.
void setBranchWeightsMetadata(WeightedBranchOpInterface op)
Sets LLVM profiling metadata for operations that have branch weights.
llvm::Instruction * lookupBranch(Operation *op) const
Finds an LLVM IR instruction that corresponds to the given MLIR operation with successors.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
LogicalResult convertArgAndResultAttrs(ArgAndResultAttrsOpInterface attrsOp, llvm::CallBase *call, ArrayRef< unsigned > immArgPositions={})
Converts argument and result attributes from attrsOp to LLVM IR attributes on the call instruction.
static std::optional< llvm::Attribute > convertNoBuiltin(llvm::LLVMContext &ctx, mlir::Attribute a)
SymbolTableCollection & symbolTable()
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
llvm::RoundingMode translateRoundingMode(LLVM::RoundingMode rounding)
Translates the given LLVM rounding mode metadata.
void setTBAAMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
Sets LLVM TBAA metadata for memory operations that have TBAA attributes.
llvm::DIExpression * translateExpression(LLVM::DIExpressionAttr attr)
Translates the given LLVM DWARF expression metadata.
llvm::OpenMPIRBuilder * getOpenMPBuilder()
Returns the OpenMP IR builder associated with the LLVM IR module being constructed.
llvm::vfs::FileSystem & getFileSystem()
Returns the virtual filesystem to use for file operations.
llvm::GlobalValue * lookupGlobal(Operation *op)
Finds an LLVM IR global value that corresponds to the given MLIR operation defining a global value.
llvm::BasicBlock * lookupBlockAddress(BlockAddressAttr attr) const
Finds the LLVM basic block that corresponds to the given BlockAddressAttr.
llvm::Metadata * translateDebugInfo(LLVM::DINodeAttr attr)
Translates the given LLVM debug info metadata.
void setDisjointFlag(Operation *op, llvm::Value *value)
Sets the disjoint flag attribute for the exported instruction value given the original operation op.
llvm::GlobalValue * lookupAlias(Operation *op)
Finds an LLVM IR global value that corresponds to the given MLIR operation defining a global alias va...
LogicalResult convertOperation(Operation &op, llvm::IRBuilderBase &builder)
Converts the given MLIR operation into LLVM IR using this translator.
llvm::Function * lookupFunction(StringRef name) const
Finds an LLVM IR function by its name.
llvm::MDNode * getOrCreateAliasScopes(ArrayRef< AliasScopeAttr > aliasScopeAttrs)
Returns the LLVM metadata corresponding to an array of mlir LLVM dialect alias scope attributes.
void mapBlock(Block *mlir, llvm::BasicBlock *llvm)
Stores the mapping between an MLIR block and LLVM IR basic block.
llvm::MDNode * getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr)
Returns the LLVM metadata corresponding to a mlir LLVM dialect alias scope attribute.
llvm::Module * getLLVMModule()
Returns the LLVM module in which the IR is being constructed.
static std::optional< llvm::Attribute > convertDefaultFuncAttr(llvm::LLVMContext &ctx, mlir::NamedAttribute namedAttr)
void forgetMapping(Region &region)
Removes the mapping for blocks contained in the region and values defined in these blocks.
void setAliasScopeMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
void setAccessGroupsMetadata(AccessGroupOpInterface op, llvm::Instruction *inst)
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
void setLoopMetadata(Operation *op, llvm::Instruction *inst)
Sets LLVM loop metadata for branch operations that have a loop annotation attribute.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
NamedAttribute represents a combination of a name and an Attribute value.
Definition Attributes.h:164
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
Definition Attributes.h:179
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Attribute getDiscardableAttr(StringRef name)
Access a discardable attribute by name, returns a null Attribute if the discardable attribute does no...
Definition Operation.h:478
Value getOperand(unsigned idx)
Definition Operation.h:375
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Definition Operation.h:559
unsigned getNumSuccessors()
Definition Operation.h:731
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
dialect_attr_range getDialectAttrs()
Return a range corresponding to the dialect attributes for this operation.
Definition Operation.h:662
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
Block * getSuccessor(unsigned index)
Definition Operation.h:733
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
This class models how operands are forwarded to block arguments in control flow.
bool empty() const
Returns true if there are no successor operands.
virtual Operation * lookupSymbolIn(Operation *symbolTableOp, StringAttr symbol)
Look up a symbol with the specified name within the specified symbol table operation,...
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
void connectPHINodes(Region &region, const ModuleTranslation &state)
For all blocks in the region that were converted to LLVM IR using the given ModuleTranslation,...
llvm::CallInst * createIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic, ArrayRef< llvm::Value * > args={}, ArrayRef< llvm::Type * > tys={})
Creates a call to an LLVM IR intrinsic function with the given arguments.
static llvm::DenseMap< llvm::StringRef, llvm::Attribute::AttrKind > getAttrNameToKindMapping()
Returns a dense map from LLVM attribute name to their kind in LLVM IR dialect.
llvm::Constant * getLLVMConstant(llvm::Type *llvmType, Attribute attr, Location loc, const ModuleTranslation &moduleTranslation)
Create an LLVM IR constant of llvmType from the MLIR attribute attr.
Operation * parentLLVMModule(Operation *op)
Lookup parent Module satisfying LLVM conditions on the Module Operation.
bool satisfiesLLVMModule(Operation *op)
LLVM requires some operations to be inside of a Module operation.
void legalizeDIExpressionsRecursively(Operation *op)
Register all known legalization patterns declared here and apply them to all ops in op.
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
void ensureDistinctSuccessors(Operation *op)
Make argument-taking successors of each block distinct.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
SetVector< Block * > getBlocksSortedByDominance(Region &region)
Gets a list of blocks that is sorted according to dominance.
DataLayoutSpecInterface translateDataLayout(const llvm::DataLayout &dataLayout, MLIRContext *context)
Translate the given LLVM data layout into an MLIR equivalent using the DLTI dialect.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:307
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:139
std::unique_ptr< llvm::Module > translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, llvm::StringRef name="LLVMDialectModule", bool disableVerification=false, llvm::vfs::FileSystem *fs=nullptr)
Translates a given LLVM dialect module into an LLVM IR module living in the given context.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120