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.CreateIntrinsicWithoutFolding(intrinsic, tys, args);
930}
931
933 llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
934 llvm::Type *retTy, ArrayRef<llvm::Value *> args) {
935 return builder.CreateIntrinsicWithoutFolding(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 Attribute attr = intrOp->getAttr(immArgName);
985 if (auto intrinsicIntegerAttr =
986 dyn_cast<LLVM::IntrinsicIntegerAttrInterface>(attr))
987 attr = intrinsicIntegerAttr.getIntegerAttr();
988 auto typedAttr = llvm::cast<TypedAttr>(attr);
989 assert(typedAttr.getType().isIntOrFloat() &&
990 "expected int or float immarg");
991 auto *type = moduleTranslation.convertType(typedAttr.getType());
992 args[immArgPos] = LLVM::detail::getLLVMConstant(
993 type, typedAttr, intrOp->getLoc(), moduleTranslation);
994 }
995 unsigned opArg = 0;
996 for (auto &arg : args) {
997 if (!arg)
998 arg = operands[opArg++];
999 }
1000
1001 // Resolve overloaded intrinsic declaration.
1002 SmallVector<llvm::Type *> overloadedTypes;
1003 for (unsigned overloadedResultIdx : overloadedResults) {
1004 if (numResults > 1) {
1005 // More than one result is mapped to an LLVM struct.
1006 overloadedTypes.push_back(moduleTranslation.convertType(
1007 llvm::cast<LLVM::LLVMStructType>(intrOp->getResult(0).getType())
1008 .getBody()[overloadedResultIdx]));
1009 } else {
1010 overloadedTypes.push_back(
1011 moduleTranslation.convertType(intrOp->getResult(0).getType()));
1012 }
1013 }
1014 for (unsigned overloadedOperandIdx : overloadedOperands)
1015 overloadedTypes.push_back(args[overloadedOperandIdx]->getType());
1016 llvm::Module *module = builder.GetInsertBlock()->getModule();
1017 llvm::Function *llvmIntr = llvm::Intrinsic::getOrInsertDeclaration(
1018 module, intrinsic, overloadedTypes);
1019
1020 return builder.CreateCall(llvmIntr, args, opBundles);
1021}
1022
1023/// Given a single MLIR operation, create the corresponding LLVM IR operation
1024/// using the `builder`.
1025LogicalResult ModuleTranslation::convertOperationImpl(
1026 Operation &op, llvm::IRBuilderBase &builder, bool recordInsertions) {
1027 const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor(&op);
1028 if (!opIface)
1029 return op.emitError("cannot be converted to LLVM IR: missing "
1030 "`LLVMTranslationDialectInterface` registration for "
1031 "dialect for op: ")
1032 << op.getName();
1033
1034 InstructionCapturingInserter::CollectionScope scope(builder,
1035 recordInsertions);
1036 if (failed(opIface->convertOperation(&op, builder, *this)))
1037 return op.emitError("LLVM Translation failed for operation: ")
1038 << op.getName();
1039
1040 return convertDialectAttributes(&op, scope.getCapturedInstructions());
1041}
1042
1043/// Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes
1044/// to define values corresponding to the MLIR block arguments. These nodes
1045/// are not connected to the source basic blocks, which may not exist yet. Uses
1046/// `builder` to construct the LLVM IR. Expects the LLVM IR basic block to have
1047/// been created for `bb` and included in the block mapping. Inserts new
1048/// instructions at the end of the block and leaves `builder` in a state
1049/// suitable for further insertion into the end of the block.
1050LogicalResult ModuleTranslation::convertBlockImpl(Block &bb,
1051 bool ignoreArguments,
1052 llvm::IRBuilderBase &builder,
1053 bool recordInsertions) {
1054 builder.SetInsertPoint(lookupBlock(&bb));
1055 auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
1056
1057 // Before traversing operations, make block arguments available through
1058 // value remapping and PHI nodes, but do not add incoming edges for the PHI
1059 // nodes just yet: those values may be defined by this or following blocks.
1060 // This step is omitted if "ignoreArguments" is set. The arguments of the
1061 // first block have been already made available through the remapping of
1062 // LLVM function arguments.
1063 if (!ignoreArguments) {
1064 auto predecessors = bb.getPredecessors();
1065 unsigned numPredecessors =
1066 std::distance(predecessors.begin(), predecessors.end());
1067 for (auto arg : bb.getArguments()) {
1068 auto wrappedType = arg.getType();
1069 if (!isCompatibleType(wrappedType))
1070 return emitError(bb.front().getLoc(),
1071 "block argument does not have an LLVM type");
1072 builder.SetCurrentDebugLocation(
1073 debugTranslation->translateLoc(arg.getLoc(), subprogram));
1074 llvm::Type *type = convertType(wrappedType);
1075 llvm::PHINode *phi = builder.CreatePHI(type, numPredecessors);
1076 mapValue(arg, phi);
1077 }
1078 }
1079
1080 // Traverse operations.
1081 for (auto &op : bb) {
1082 // Set the current debug location within the builder.
1083 builder.SetCurrentDebugLocation(
1084 debugTranslation->translateLoc(op.getLoc(), subprogram));
1085
1086 if (failed(convertOperationImpl(op, builder, recordInsertions)))
1087 return failure();
1088
1089 // Set the branch weight metadata on the translated instruction.
1090 if (auto iface = dyn_cast<WeightedBranchOpInterface>(op))
1092 }
1093
1094 return success();
1095}
1096
1097/// A helper method to get the single Block in an operation honoring LLVM's
1098/// module requirements.
1100 return module->getRegion(0).front();
1101}
1102
1103/// A helper method to decide if a constant must not be set as a global variable
1104/// initializer. For an external linkage variable, the variable with an
1105/// initializer is considered externally visible and defined in this module, the
1106/// variable without an initializer is externally available and is defined
1107/// elsewhere.
1108static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage,
1109 llvm::Constant *cst) {
1110 return (linkage == llvm::GlobalVariable::ExternalLinkage && !cst) ||
1111 linkage == llvm::GlobalVariable::ExternalWeakLinkage;
1112}
1113
1114/// Sets the runtime preemption specifier of `gv` to dso_local if
1115/// `dsoLocalRequested` is true, otherwise it is left unchanged.
1116static void addRuntimePreemptionSpecifier(bool dsoLocalRequested,
1117 llvm::GlobalValue *gv) {
1118 if (dsoLocalRequested)
1119 gv->setDSOLocal(true);
1120}
1121
1122/// Attempts to translate an MLIR attribute identified by `key`, optionally with
1123/// the given `value`, into an LLVM IR attribute. Reports errors at `loc` if
1124/// any. If the attribute name corresponds to a known LLVM IR attribute kind,
1125/// creates the LLVM attribute of that kind; otherwise, keeps it as a string
1126/// attribute. Performs additional checks for attributes known to have or not
1127/// have a value in order to avoid assertions inside LLVM upon construction.
1128static FailureOr<llvm::Attribute>
1129convertMLIRAttributeToLLVM(Location loc, llvm::LLVMContext &ctx, StringRef key,
1130 StringRef value = StringRef()) {
1131 auto kind = llvm::Attribute::getAttrKindFromName(key);
1132 if (kind == llvm::Attribute::None)
1133 return llvm::Attribute::get(ctx, key, value);
1134
1135 if (llvm::Attribute::isIntAttrKind(kind)) {
1136 if (value.empty())
1137 return emitError(loc) << "LLVM attribute '" << key << "' expects a value";
1138
1140 if (!value.getAsInteger(/*Radix=*/0, result))
1141 return llvm::Attribute::get(ctx, kind, result);
1142 return llvm::Attribute::get(ctx, key, value);
1143 }
1144
1145 if (!value.empty())
1146 return emitError(loc) << "LLVM attribute '" << key
1147 << "' does not expect a value, found '" << value
1148 << "'";
1149
1150 return llvm::Attribute::get(ctx, kind);
1151}
1152
1153/// Converts the MLIR attributes listed in the given array attribute into LLVM
1154/// attributes. Returns an `AttrBuilder` containing the converted attributes.
1155/// Reports error to `loc` if any and returns immediately. Expects `arrayAttr`
1156/// to contain either string attributes, treated as value-less LLVM attributes,
1157/// or array attributes containing two string attributes, with the first string
1158/// being the name of the corresponding LLVM attribute and the second string
1159/// beings its value. Note that even integer attributes are expected to have
1160/// their values expressed as strings.
1161static FailureOr<llvm::AttrBuilder>
1162convertMLIRAttributesToLLVM(Location loc, llvm::LLVMContext &ctx,
1163 ArrayAttr arrayAttr, StringRef arrayAttrName) {
1164 llvm::AttrBuilder attrBuilder(ctx);
1165 if (!arrayAttr)
1166 return attrBuilder;
1167
1168 for (Attribute attr : arrayAttr) {
1169 if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
1170 FailureOr<llvm::Attribute> llvmAttr =
1171 convertMLIRAttributeToLLVM(loc, ctx, stringAttr.getValue());
1172 if (failed(llvmAttr))
1173 return failure();
1174 attrBuilder.addAttribute(*llvmAttr);
1175 continue;
1176 }
1177
1178 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1179 if (!arrayAttr || arrayAttr.size() != 2)
1180 return emitError(loc) << "expected '" << arrayAttrName
1181 << "' to contain string or array attributes";
1182
1183 auto keyAttr = dyn_cast<StringAttr>(arrayAttr[0]);
1184 auto valueAttr = dyn_cast<StringAttr>(arrayAttr[1]);
1185 if (!keyAttr || !valueAttr)
1186 return emitError(loc) << "expected arrays within '" << arrayAttrName
1187 << "' to contain two strings";
1188
1189 FailureOr<llvm::Attribute> llvmAttr = convertMLIRAttributeToLLVM(
1190 loc, ctx, keyAttr.getValue(), valueAttr.getValue());
1191 if (failed(llvmAttr))
1192 return failure();
1193 attrBuilder.addAttribute(*llvmAttr);
1194 }
1195
1196 return attrBuilder;
1197}
1198
1199LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
1200 // Mapping from compile unit to its respective set of global variables.
1202
1203 // First, create all global variables and global aliases in LLVM IR. A global
1204 // or alias body may refer to another global/alias or itself, so all the
1205 // mapping needs to happen prior to body conversion.
1206
1207 // Create all llvm::GlobalVariable
1208 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1209 llvm::Type *type = convertType(op.getType());
1210 llvm::Constant *cst = nullptr;
1211 const bool deferValueAttrToPass2 = op.getValueOrNull() &&
1212 !op.getInitializerBlock() &&
1213 !isa<StringAttr>(op.getValueOrNull());
1214 if (op.getValueOrNull() && !deferValueAttrToPass2) {
1215 // String attributes are treated separately because they cannot appear as
1216 // in-function constants and are thus not supported by getLLVMConstant.
1217 if (auto strAttr = dyn_cast_or_null<StringAttr>(op.getValueOrNull())) {
1218 cst = llvm::ConstantDataArray::getString(
1219 llvmModule->getContext(), strAttr.getValue(), /*AddNull=*/false);
1220 type = cst->getType();
1221 }
1222 }
1223
1224 auto linkage = convertLinkageToLLVM(op.getLinkage());
1225
1226 // LLVM IR requires constant with linkage other than external or weak
1227 // external to have initializers. If MLIR does not provide an initializer,
1228 // default to undef.
1229 bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
1230 if (!deferValueAttrToPass2) {
1231 if (!dropInitializer && !cst)
1232 cst = llvm::UndefValue::get(type);
1233 else if (dropInitializer && cst)
1234 cst = nullptr;
1235 } else {
1236 cst = nullptr;
1237 }
1238
1239 auto *var = new llvm::GlobalVariable(
1240 *llvmModule, type, op.getConstant(), linkage, cst, op.getSymName(),
1241 /*InsertBefore=*/nullptr,
1242 op.getThreadLocal_() ? llvm::GlobalValue::GeneralDynamicTLSModel
1243 : llvm::GlobalValue::NotThreadLocal,
1244 op.getAddrSpace(), op.getExternallyInitialized());
1245
1246 if (std::optional<mlir::SymbolRefAttr> comdat = op.getComdat()) {
1247 auto selectorOp = cast<ComdatSelectorOp>(
1249 var->setComdat(comdatMapping.lookup(selectorOp));
1250 }
1251
1252 if (op.getUnnamedAddr().has_value())
1253 var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
1254
1255 if (op.getSection().has_value())
1256 var->setSection(*op.getSection());
1257
1258 addRuntimePreemptionSpecifier(op.getDsoLocal(), var);
1259
1260 std::optional<uint64_t> alignment = op.getAlignment();
1261 if (alignment.has_value())
1262 var->setAlignment(llvm::MaybeAlign(alignment.value()));
1263
1264 var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
1265
1266 globalsMapping.try_emplace(op, var);
1267 globalsByNameMapping.try_emplace(op.getSymName(), var);
1268
1269 // Add debug information if present.
1270 if (op.getDbgExprs()) {
1271 for (auto exprAttr :
1272 op.getDbgExprs()->getAsRange<DIGlobalVariableExpressionAttr>()) {
1273 llvm::DIGlobalVariableExpression *diGlobalExpr =
1274 debugTranslation->translateGlobalVariableExpression(exprAttr);
1275 llvm::DIGlobalVariable *diGlobalVar = diGlobalExpr->getVariable();
1276 var->addDebugInfo(diGlobalExpr);
1277
1278 // There is no `globals` field in DICompileUnitAttr which can be
1279 // directly assigned to DICompileUnit. We have to build the list by
1280 // looking at the dbgExpr of all the GlobalOps. The scope of the
1281 // variable is used to get the DICompileUnit in which to add it. But
1282 // there are cases where the scope of a global does not directly point
1283 // to the DICompileUnit and we have to do a bit more work to get to
1284 // it. Some of those cases are:
1285 //
1286 // 1. For the languages that support modules, the scope hierarchy can
1287 // be variable -> DIModule -> DICompileUnit
1288 //
1289 // 2. For the Fortran common block variable, the scope hierarchy can
1290 // be variable -> DICommonBlock -> DISubprogram -> DICompileUnit
1291 //
1292 // 3. For entities like static local variables in C or variable with
1293 // SAVE attribute in Fortran, the scope hierarchy can be
1294 // variable -> DISubprogram -> DICompileUnit
1295 llvm::DIScope *scope = diGlobalVar->getScope();
1296 if (auto *mod = dyn_cast_if_present<llvm::DIModule>(scope))
1297 scope = mod->getScope();
1298 else if (auto *cb = dyn_cast_if_present<llvm::DICommonBlock>(scope)) {
1299 if (auto *sp =
1300 dyn_cast_if_present<llvm::DISubprogram>(cb->getScope()))
1301 scope = sp->getUnit();
1302 } else if (auto *sp = dyn_cast_if_present<llvm::DISubprogram>(scope))
1303 scope = sp->getUnit();
1304
1305 // Get the compile unit (scope) of the the global variable.
1306 if (llvm::DICompileUnit *compileUnit =
1307 dyn_cast_if_present<llvm::DICompileUnit>(scope)) {
1308 // Update the compile unit with this incoming global variable
1309 // expression during the finalizing step later.
1310 allGVars[compileUnit].push_back(diGlobalExpr);
1311 }
1312 }
1313 }
1314
1315 // Forward the target-specific attributes to LLVM.
1316 FailureOr<llvm::AttrBuilder> convertedTargetSpecificAttrs =
1318 op.getTargetSpecificAttrsAttr(),
1319 op.getTargetSpecificAttrsAttrName());
1320 if (failed(convertedTargetSpecificAttrs))
1321 return failure();
1322 var->addAttributes(*convertedTargetSpecificAttrs);
1323 }
1324
1325 // Value-attribute initializers may reference other globals by symbol name.
1326 // Register every global above before materializing those constants.
1327 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1328 if (!op.getValueOrNull() || op.getInitializerBlock() ||
1329 isa<StringAttr>(op.getValueOrNull()))
1330 continue;
1331
1332 llvm::Type *type = convertType(op.getType());
1333 llvm::Constant *cst =
1334 getLLVMConstant(type, op.getValueOrNull(), op.getLoc(), *this);
1335 if (!cst)
1336 return failure();
1337
1338 auto linkage = convertLinkageToLLVM(op.getLinkage());
1339 bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
1340 auto *var = cast<llvm::GlobalVariable>(lookupGlobal(op));
1341 if (dropInitializer)
1342 var->setInitializer(nullptr);
1343 else
1344 var->setInitializer(cst);
1345 }
1346
1347 // Create all llvm::GlobalAlias
1348 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
1349 llvm::Type *type = convertType(op.getType());
1350 llvm::Constant *cst = nullptr;
1351 llvm::GlobalValue::LinkageTypes linkage =
1352 convertLinkageToLLVM(op.getLinkage());
1353 llvm::Module &llvmMod = *llvmModule;
1354
1355 // Note address space and aliasee info isn't set just yet.
1356 llvm::GlobalAlias *var = llvm::GlobalAlias::create(
1357 type, op.getAddrSpace(), linkage, op.getSymName(), /*placeholder*/ cst,
1358 &llvmMod);
1359
1360 var->setThreadLocalMode(op.getThreadLocal_()
1361 ? llvm::GlobalAlias::GeneralDynamicTLSModel
1362 : llvm::GlobalAlias::NotThreadLocal);
1363
1364 // Note there is no need to setup the comdat because GlobalAlias calls into
1365 // the aliasee comdat information automatically.
1366
1367 if (op.getUnnamedAddr().has_value())
1368 var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
1369
1370 var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
1371
1372 aliasesMapping.try_emplace(op, var);
1373 }
1374
1375 // Convert global variable bodies.
1376 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1377 if (Block *initializer = op.getInitializerBlock()) {
1378 llvm::IRBuilder<llvm::TargetFolder> builder(
1379 llvmModule->getContext(),
1380 llvm::TargetFolder(llvmModule->getDataLayout()));
1381
1382 [[maybe_unused]] int numConstantsHit = 0;
1383 [[maybe_unused]] int numConstantsErased = 0;
1384 DenseMap<llvm::ConstantAggregate *, int> constantAggregateUseMap;
1385
1386 for (auto &op : initializer->without_terminator()) {
1387 if (failed(convertOperation(op, builder)))
1388 return emitError(op.getLoc(), "fail to convert global initializer");
1389 auto *cst = dyn_cast<llvm::Constant>(lookupValue(op.getResult(0)));
1390 if (!cst)
1391 return emitError(op.getLoc(), "unemittable constant value");
1392
1393 // When emitting an LLVM constant, a new constant is created and the old
1394 // constant may become dangling and take space. We should remove the
1395 // dangling constants to avoid memory explosion especially for constant
1396 // arrays whose number of elements is large.
1397 // Because multiple operations may refer to the same constant, we need
1398 // to count the number of uses of each constant array and remove it only
1399 // when the count becomes zero.
1400 if (auto *agg = dyn_cast<llvm::ConstantAggregate>(cst)) {
1401 numConstantsHit++;
1402 Value result = op.getResult(0);
1403 int numUsers = std::distance(result.use_begin(), result.use_end());
1404 auto [iterator, inserted] =
1405 constantAggregateUseMap.try_emplace(agg, numUsers);
1406 if (!inserted) {
1407 // Key already exists, update the value
1408 iterator->second += numUsers;
1409 }
1410 }
1411 // Scan the operands of the operation to decrement the use count of
1412 // constants. Erase the constant if the use count becomes zero.
1413 for (Value v : op.getOperands()) {
1414 auto *cst = dyn_cast<llvm::ConstantAggregate>(lookupValue(v));
1415 if (!cst)
1416 continue;
1417 auto iter = constantAggregateUseMap.find(cst);
1418 assert(iter != constantAggregateUseMap.end() && "constant not found");
1419 iter->second--;
1420 if (iter->second == 0) {
1421 // NOTE: cannot call removeDeadConstantUsers() here because it
1422 // may remove the constant which has uses not be converted yet.
1423 if (cst->user_empty()) {
1424 cst->destroyConstant();
1425 numConstantsErased++;
1426 }
1427 constantAggregateUseMap.erase(iter);
1428 }
1429 }
1430 }
1431
1432 ReturnOp ret = cast<ReturnOp>(initializer->getTerminator());
1433 llvm::Constant *cst =
1434 cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
1435 auto *global = cast<llvm::GlobalVariable>(lookupGlobal(op));
1436 if (!shouldDropGlobalInitializer(global->getLinkage(), cst))
1437 global->setInitializer(cst);
1438
1439 // Try to remove the dangling constants again after all operations are
1440 // converted.
1441 for (auto it : constantAggregateUseMap) {
1442 auto *cst = it.first;
1443 cst->removeDeadConstantUsers();
1444 if (cst->user_empty()) {
1445 cst->destroyConstant();
1446 numConstantsErased++;
1447 }
1448 }
1449
1450 LLVM_DEBUG(llvm::dbgs()
1451 << "Convert initializer for " << op.getName() << "\n";
1452 llvm::dbgs() << numConstantsHit << " new constants hit\n";
1453 llvm::dbgs()
1454 << numConstantsErased << " dangling constants erased\n";);
1455 }
1456 }
1457
1458 // Convert llvm.mlir.global_ctors and dtors.
1459 for (Operation &op : getModuleBody(mlirModule)) {
1460 auto ctorOp = dyn_cast<GlobalCtorsOp>(op);
1461 auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
1462 if (!ctorOp && !dtorOp)
1463 continue;
1464
1465 // The empty / zero initialized version of llvm.global_(c|d)tors cannot be
1466 // handled by appendGlobalFn logic below, which just ignores empty (c|d)tor
1467 // lists. Make sure it gets emitted.
1468 if ((ctorOp && ctorOp.getCtors().empty()) ||
1469 (dtorOp && dtorOp.getDtors().empty())) {
1470 llvm::IRBuilder<llvm::TargetFolder> builder(
1471 llvmModule->getContext(),
1472 llvm::TargetFolder(llvmModule->getDataLayout()));
1473 llvm::Type *eltTy = llvm::StructType::get(
1474 builder.getInt32Ty(), builder.getPtrTy(), builder.getPtrTy());
1475 llvm::ArrayType *at = llvm::ArrayType::get(eltTy, 0);
1476 llvm::Constant *zeroInit = llvm::Constant::getNullValue(at);
1477 (void)new llvm::GlobalVariable(
1478 *llvmModule, zeroInit->getType(), false,
1479 llvm::GlobalValue::AppendingLinkage, zeroInit,
1480 ctorOp ? "llvm.global_ctors" : "llvm.global_dtors");
1481 } else {
1482 auto range = ctorOp
1483 ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
1484 : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
1485 auto appendGlobalFn =
1486 ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
1487 for (const auto &[sym, prio] : range) {
1488 llvm::Function *f =
1489 lookupFunction(cast<FlatSymbolRefAttr>(sym).getValue());
1490 appendGlobalFn(*llvmModule, f, cast<IntegerAttr>(prio).getInt(),
1491 /*Data=*/nullptr);
1492 }
1493 }
1494 }
1495
1496 for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>())
1497 if (failed(convertDialectAttributes(op, {})))
1498 return failure();
1499
1500 // Finally, update the compile units their respective sets of global variables
1501 // created earlier.
1502 for (const auto &[compileUnit, globals] : allGVars) {
1503 compileUnit->replaceGlobalVariables(
1504 llvm::MDTuple::get(getLLVMContext(), globals));
1505 }
1506
1507 // Convert global alias bodies.
1508 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>()) {
1509 Block &initializer = op.getInitializerBlock();
1510 llvm::IRBuilder<llvm::TargetFolder> builder(
1511 llvmModule->getContext(),
1512 llvm::TargetFolder(llvmModule->getDataLayout()));
1513
1514 for (mlir::Operation &op : initializer.without_terminator()) {
1515 if (failed(convertOperation(op, builder)))
1516 return emitError(op.getLoc(), "fail to convert alias initializer");
1517 if (!isa<llvm::Constant>(lookupValue(op.getResult(0))))
1518 return emitError(op.getLoc(), "unemittable constant value");
1519 }
1520
1521 auto ret = cast<ReturnOp>(initializer.getTerminator());
1522 auto *cst = cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
1523 assert(aliasesMapping.count(op));
1524 auto *alias = cast<llvm::GlobalAlias>(aliasesMapping[op]);
1525 alias->setAliasee(cst);
1526 }
1527
1528 for (auto op : getModuleBody(mlirModule).getOps<LLVM::AliasOp>())
1529 if (failed(convertDialectAttributes(op, {})))
1530 return failure();
1531
1532 return success();
1533}
1534
1535/// Return a representation of `value` as metadata.
1536static llvm::Metadata *convertIntegerToMetadata(llvm::LLVMContext &context,
1537 const llvm::APInt &value) {
1538 llvm::Constant *constant = llvm::ConstantInt::get(context, value);
1539 return llvm::ConstantAsMetadata::get(constant);
1540}
1541
1542/// Return a representation of `value` as an MDNode.
1543static llvm::MDNode *convertIntegerToMDNode(llvm::LLVMContext &context,
1544 const llvm::APInt &value) {
1545 return llvm::MDNode::get(context, convertIntegerToMetadata(context, value));
1546}
1547
1548/// Return an MDNode encoding `vec_type_hint` metadata.
1549static llvm::MDNode *convertVecTypeHintToMDNode(llvm::LLVMContext &context,
1550 llvm::Type *type,
1551 bool isSigned) {
1552 llvm::Metadata *typeMD =
1553 llvm::ConstantAsMetadata::get(llvm::UndefValue::get(type));
1554 llvm::Metadata *isSignedMD =
1555 convertIntegerToMetadata(context, llvm::APInt(32, isSigned ? 1 : 0));
1556 return llvm::MDNode::get(context, {typeMD, isSignedMD});
1557}
1558
1559/// Return an MDNode with a tuple given by the values in `values`.
1560static llvm::MDNode *convertIntegerArrayToMDNode(llvm::LLVMContext &context,
1561 ArrayRef<int32_t> values) {
1563 llvm::transform(
1564 values, std::back_inserter(mdValues), [&context](int32_t value) {
1565 return convertIntegerToMetadata(context, llvm::APInt(32, value));
1566 });
1567 return llvm::MDNode::get(context, mdValues);
1568}
1569
1570LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
1571 // Clear the block, branch value mappings, they are only relevant within one
1572 // function.
1573 blockMapping.clear();
1574 valueMapping.clear();
1575 branchMapping.clear();
1576 llvm::Function *llvmFunc = lookupFunction(func.getName());
1577 llvm::LLVMContext &llvmContext = llvmFunc->getContext();
1578
1579 // Add function arguments to the value remapping table.
1580 for (auto [mlirArg, llvmArg] :
1581 llvm::zip(func.getArguments(), llvmFunc->args()))
1582 mapValue(mlirArg, &llvmArg);
1583
1584 // Check the personality and set it.
1585 if (func.getPersonality()) {
1586 llvm::Type *ty = llvm::PointerType::getUnqual(llvmFunc->getContext());
1587 if (llvm::Constant *pfunc = getLLVMConstant(ty, func.getPersonalityAttr(),
1588 func.getLoc(), *this))
1589 llvmFunc->setPersonalityFn(pfunc);
1590 }
1591
1592 if (std::optional<StringRef> section = func.getSection())
1593 llvmFunc->setSection(*section);
1594
1595 if (func.getArmStreaming())
1596 llvmFunc->addFnAttr("aarch64_pstate_sm_enabled");
1597 else if (func.getArmLocallyStreaming())
1598 llvmFunc->addFnAttr("aarch64_pstate_sm_body");
1599 else if (func.getArmStreamingCompatible())
1600 llvmFunc->addFnAttr("aarch64_pstate_sm_compatible");
1601
1602 if (func.getArmNewZa())
1603 llvmFunc->addFnAttr("aarch64_new_za");
1604 else if (func.getArmInZa())
1605 llvmFunc->addFnAttr("aarch64_in_za");
1606 else if (func.getArmOutZa())
1607 llvmFunc->addFnAttr("aarch64_out_za");
1608 else if (func.getArmInoutZa())
1609 llvmFunc->addFnAttr("aarch64_inout_za");
1610 else if (func.getArmPreservesZa())
1611 llvmFunc->addFnAttr("aarch64_preserves_za");
1612
1613 if (auto targetCpu = func.getTargetCpu())
1614 llvmFunc->addFnAttr("target-cpu", *targetCpu);
1615
1616 if (auto tuneCpu = func.getTuneCpu())
1617 llvmFunc->addFnAttr("tune-cpu", *tuneCpu);
1618
1619 if (auto reciprocalEstimates = func.getReciprocalEstimates())
1620 llvmFunc->addFnAttr("reciprocal-estimates", *reciprocalEstimates);
1621
1622 if (auto preferVectorWidth = func.getPreferVectorWidth())
1623 llvmFunc->addFnAttr("prefer-vector-width", *preferVectorWidth);
1624
1625 if (func.getUseSampleProfile())
1626 llvmFunc->addFnAttr("use-sample-profile");
1627
1628 if (auto attr = func.getVscaleRange())
1629 llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
1630 getLLVMContext(), attr->getMinRange().getInt(),
1631 attr->getMaxRange().getInt()));
1632
1633 if (auto noSignedZerosFpMath = func.getNoSignedZerosFpMath())
1634 llvmFunc->addFnAttr("no-signed-zeros-fp-math",
1635 llvm::toStringRef(*noSignedZerosFpMath));
1636
1637 if (auto fpContract = func.getFpContract())
1638 llvmFunc->addFnAttr("fp-contract", *fpContract);
1639
1640 if (auto instrumentFunctionEntry = func.getInstrumentFunctionEntry())
1641 llvmFunc->addFnAttr("instrument-function-entry", *instrumentFunctionEntry);
1642
1643 if (auto instrumentFunctionExit = func.getInstrumentFunctionExit())
1644 llvmFunc->addFnAttr("instrument-function-exit", *instrumentFunctionExit);
1645
1646 // First, create all blocks so we can jump to them.
1647 for (auto &bb : func) {
1648 auto *llvmBB = llvm::BasicBlock::Create(llvmContext);
1649 llvmBB->insertInto(llvmFunc);
1650 mapBlock(&bb, llvmBB);
1651 }
1652
1653 // Then, convert blocks one by one in topological order to ensure defs are
1654 // converted before uses.
1655 auto blocks = getBlocksSortedByDominance(func.getBody());
1656 for (Block *bb : blocks) {
1657 CapturingIRBuilder builder(llvmContext,
1658 llvm::TargetFolder(llvmModule->getDataLayout()));
1659 if (failed(convertBlockImpl(*bb, bb->isEntryBlock(), builder,
1660 /*recordInsertions=*/true)))
1661 return failure();
1662 }
1663
1664 // After all blocks have been traversed and values mapped, connect the PHI
1665 // nodes to the results of preceding blocks.
1666 detail::connectPHINodes(func.getBody(), *this);
1667
1668 // Finally, convert dialect attributes attached to the function.
1669 return convertDialectAttributes(func, {});
1670}
1671
1672LogicalResult ModuleTranslation::convertDialectAttributes(
1673 Operation *op, ArrayRef<llvm::Instruction *> instructions) {
1674 for (NamedAttribute attribute : op->getDialectAttrs())
1675 if (failed(iface.amendOperation(op, instructions, attribute, *this)))
1676 return failure();
1677 return success();
1678}
1679
1680/// Converts memory effect attributes from `func` and attaches them to
1681/// `llvmFunc`.
1683 llvm::Function *llvmFunc) {
1684 if (!func.getMemoryEffects())
1685 return;
1686
1687 MemoryEffectsAttr memEffects = func.getMemoryEffectsAttr();
1688
1689 // Add memory effects incrementally.
1690 llvm::MemoryEffects newMemEffects =
1691 llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
1692 convertModRefInfoToLLVM(memEffects.getArgMem()));
1693 newMemEffects |= llvm::MemoryEffects(
1694 llvm::MemoryEffects::Location::InaccessibleMem,
1695 convertModRefInfoToLLVM(memEffects.getInaccessibleMem()));
1696 newMemEffects |=
1697 llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
1698 convertModRefInfoToLLVM(memEffects.getOther()));
1699 newMemEffects |=
1700 llvm::MemoryEffects(llvm::MemoryEffects::Location::ErrnoMem,
1701 convertModRefInfoToLLVM(memEffects.getErrnoMem()));
1702 newMemEffects |=
1703 llvm::MemoryEffects(llvm::MemoryEffects::Location::TargetMem0,
1704 convertModRefInfoToLLVM(memEffects.getTargetMem0()));
1705 newMemEffects |=
1706 llvm::MemoryEffects(llvm::MemoryEffects::Location::TargetMem1,
1707 convertModRefInfoToLLVM(memEffects.getTargetMem1()));
1708 llvmFunc->setMemoryEffects(newMemEffects);
1709}
1710
1711llvm::Attribute
1713 if (!allocSizeAttr || allocSizeAttr.empty())
1714 return llvm::Attribute{};
1715
1716 unsigned elemSize = static_cast<unsigned>(allocSizeAttr[0]);
1717 std::optional<unsigned> numElems;
1718 if (allocSizeAttr.size() > 1)
1719 numElems = static_cast<unsigned>(allocSizeAttr[1]);
1720
1721 return llvm::Attribute::getWithAllocSizeArgs(getLLVMContext(), elemSize,
1722 numElems);
1723}
1725 llvm::AttrBuilder &Attrs) {
1726 std::optional<DenormalFPEnvAttr> denormalFpEnv = func.getDenormalFpenv();
1727 if (!denormalFpEnv)
1728 return;
1729
1730 llvm::DenormalMode DefaultMode(
1731 convertDenormalModeKindToLLVM(denormalFpEnv->getDefaultOutputMode()),
1732 convertDenormalModeKindToLLVM(denormalFpEnv->getDefaultInputMode()));
1733 llvm::DenormalMode FloatMode(
1734 convertDenormalModeKindToLLVM(denormalFpEnv->getFloatOutputMode()),
1735 convertDenormalModeKindToLLVM(denormalFpEnv->getFloatInputMode()));
1736
1737 llvm::DenormalFPEnv FPEnv(DefaultMode, FloatMode);
1738 Attrs.addDenormalFPEnvAttr(FPEnv);
1739}
1740
1741/// Converts function attributes from `func` and attaches them to `llvmFunc`.
1743 llvm::Function *llvmFunc) {
1744 // FIXME: Use AttrBuilder far all cases
1745 llvm::AttrBuilder AttrBuilder(llvmFunc->getContext());
1746
1747 if (func.getNoInlineAttr())
1748 llvmFunc->addFnAttr(llvm::Attribute::NoInline);
1749 if (func.getAlwaysInlineAttr())
1750 llvmFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1751 if (func.getInlineHintAttr())
1752 llvmFunc->addFnAttr(llvm::Attribute::InlineHint);
1753 if (func.getOptimizeNoneAttr())
1754 llvmFunc->addFnAttr(llvm::Attribute::OptimizeNone);
1755 if (func.getReturnsTwiceAttr())
1756 llvmFunc->addFnAttr(llvm::Attribute::ReturnsTwice);
1757 if (func.getColdAttr())
1758 llvmFunc->addFnAttr(llvm::Attribute::Cold);
1759 if (func.getHotAttr())
1760 llvmFunc->addFnAttr(llvm::Attribute::Hot);
1761 if (func.getNoduplicateAttr())
1762 llvmFunc->addFnAttr(llvm::Attribute::NoDuplicate);
1763 if (func.getConvergentAttr())
1764 llvmFunc->addFnAttr(llvm::Attribute::Convergent);
1765 if (func.getNoUnwindAttr())
1766 llvmFunc->addFnAttr(llvm::Attribute::NoUnwind);
1767 if (func.getWillReturnAttr())
1768 llvmFunc->addFnAttr(llvm::Attribute::WillReturn);
1769 if (func.getNoreturnAttr())
1770 llvmFunc->addFnAttr(llvm::Attribute::NoReturn);
1771 if (func.getOptsizeAttr())
1772 llvmFunc->addFnAttr(llvm::Attribute::OptimizeForSize);
1773 if (func.getMinsizeAttr())
1774 llvmFunc->addFnAttr(llvm::Attribute::MinSize);
1775 if (func.getSaveRegParamsAttr())
1776 llvmFunc->addFnAttr("save-reg-params");
1777 if (func.getNoCallerSavedRegistersAttr())
1778 llvmFunc->addFnAttr("no_caller_saved_registers");
1779 if (func.getNocallbackAttr())
1780 llvmFunc->addFnAttr(llvm::Attribute::NoCallback);
1781 if (StringAttr modFormat = func.getModularFormatAttr())
1782 llvmFunc->addFnAttr("modular-format", modFormat.getValue());
1783 if (TargetFeaturesAttr targetFeatAttr = func.getTargetFeaturesAttr())
1784 llvmFunc->addFnAttr("target-features", targetFeatAttr.getFeaturesString());
1785 if (FramePointerKindAttr fpAttr = func.getFramePointerAttr())
1786 llvmFunc->addFnAttr("frame-pointer", stringifyFramePointerKind(
1787 fpAttr.getFramePointerKind()));
1788 if (UWTableKindAttr uwTableKindAttr = func.getUwtableKindAttr())
1789 llvmFunc->setUWTableKind(
1790 convertUWTableKindToLLVM(uwTableKindAttr.getUwtableKind()));
1791 if (StringAttr zcsr = func.getZeroCallUsedRegsAttr())
1792 llvmFunc->addFnAttr("zero-call-used-regs", zcsr.getValue());
1793
1794 if (ArrayAttr noBuiltins = func.getNobuiltinsAttr()) {
1795 if (noBuiltins.empty())
1796 llvmFunc->addFnAttr("no-builtins");
1797
1798 mod.convertFunctionAttrCollection(noBuiltins, llvmFunc,
1800 }
1801
1802 mod.convertFunctionAttrCollection(func.getDefaultFuncAttrsAttr(), llvmFunc,
1804
1805 if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr());
1806 attr.isValid())
1807 llvmFunc->addFnAttr(attr);
1808
1810
1811 convertDenormalFPEnvAttribute(func, AttrBuilder);
1812 llvmFunc->addFnAttrs(AttrBuilder);
1813}
1814
1815/// Converts function attributes from `func` and attaches them to `llvmFunc`.
1817 llvm::Function *llvmFunc,
1818 ModuleTranslation &translation) {
1819 llvm::LLVMContext &llvmContext = llvmFunc->getContext();
1820
1821 if (VecTypeHintAttr vecTypeHint = func.getVecTypeHintAttr()) {
1822 Type type = vecTypeHint.getHint().getValue();
1823 llvm::Type *llvmType = translation.convertType(type);
1824 bool isSigned = vecTypeHint.getIsSigned();
1825 llvmFunc->setMetadata(
1826 func.getVecTypeHintAttrName(),
1827 convertVecTypeHintToMDNode(llvmContext, llvmType, isSigned));
1828 }
1829
1830 if (std::optional<ArrayRef<int32_t>> workGroupSizeHint =
1831 func.getWorkGroupSizeHint()) {
1832 llvmFunc->setMetadata(
1833 func.getWorkGroupSizeHintAttrName(),
1834 convertIntegerArrayToMDNode(llvmContext, *workGroupSizeHint));
1835 }
1836
1837 if (std::optional<ArrayRef<int32_t>> reqdWorkGroupSize =
1838 func.getReqdWorkGroupSize()) {
1839 llvmFunc->setMetadata(
1840 func.getReqdWorkGroupSizeAttrName(),
1841 convertIntegerArrayToMDNode(llvmContext, *reqdWorkGroupSize));
1842 }
1843
1844 if (std::optional<uint32_t> intelReqdSubGroupSize =
1845 func.getIntelReqdSubGroupSize()) {
1846 llvmFunc->setMetadata(
1847 func.getIntelReqdSubGroupSizeAttrName(),
1848 convertIntegerToMDNode(llvmContext,
1849 llvm::APInt(32, *intelReqdSubGroupSize)));
1850 }
1851}
1852
1853static LogicalResult convertParameterAttr(llvm::AttrBuilder &attrBuilder,
1854 llvm::Attribute::AttrKind llvmKind,
1855 NamedAttribute namedAttr,
1856 ModuleTranslation &moduleTranslation,
1857 Location loc) {
1859 .Case([&](TypeAttr typeAttr) {
1860 attrBuilder.addTypeAttr(
1861 llvmKind, moduleTranslation.convertType(typeAttr.getValue()));
1862 return success();
1863 })
1864 .Case([&](IntegerAttr intAttr) {
1865 attrBuilder.addRawIntAttr(llvmKind, intAttr.getInt());
1866 return success();
1867 })
1868 .Case([&](UnitAttr) {
1869 attrBuilder.addAttribute(llvmKind);
1870 return success();
1871 })
1872 .Case([&](LLVM::ConstantRangeAttr rangeAttr) {
1873 attrBuilder.addConstantRangeAttr(
1874 llvmKind,
1875 llvm::ConstantRange(rangeAttr.getLower(), rangeAttr.getUpper()));
1876 return success();
1877 })
1878 .Default([loc](auto) {
1879 return emitError(loc, "unsupported parameter attribute type");
1880 });
1881}
1882
1883FailureOr<llvm::AttrBuilder>
1884ModuleTranslation::convertParameterAttrs(LLVMFuncOp func, int argIdx,
1885 DictionaryAttr paramAttrs) {
1886 llvm::AttrBuilder attrBuilder(llvmModule->getContext());
1887 auto attrNameToKindMapping = getAttrNameToKindMapping();
1888 Location loc = func.getLoc();
1889
1890 for (auto namedAttr : paramAttrs) {
1891 auto it = attrNameToKindMapping.find(namedAttr.getName());
1892 if (it != attrNameToKindMapping.end()) {
1893 llvm::Attribute::AttrKind llvmKind = it->second;
1894 if (failed(convertParameterAttr(attrBuilder, llvmKind, namedAttr, *this,
1895 loc)))
1896 return failure();
1897 } else if (namedAttr.getNameDialect()) {
1898 if (failed(iface.convertParameterAttr(func, argIdx, namedAttr, *this)))
1899 return failure();
1900 }
1901 }
1902
1903 return attrBuilder;
1904}
1905
1907 ArgAndResultAttrsOpInterface attrsOp, llvm::CallBase *call,
1908 ArrayRef<unsigned> immArgPositions) {
1909 // Convert the argument attributes.
1910 if (ArrayAttr argAttrsArray = attrsOp.getArgAttrsAttr()) {
1911 unsigned argAttrIdx = 0;
1912 llvm::SmallDenseSet<unsigned> immArgPositionsSet(immArgPositions.begin(),
1913 immArgPositions.end());
1914 for (unsigned argIdx : llvm::seq<unsigned>(call->arg_size())) {
1915 if (argAttrIdx >= argAttrsArray.size())
1916 break;
1917 // Skip immediate arguments (they have no entries in argAttrsArray).
1918 if (immArgPositionsSet.contains(argIdx))
1919 continue;
1920 // Skip empty argument attributes.
1921 auto argAttrs = cast<DictionaryAttr>(argAttrsArray[argAttrIdx++]);
1922 if (argAttrs.empty())
1923 continue;
1924 // Convert and add attributes to the call instruction.
1925 FailureOr<llvm::AttrBuilder> attrBuilder =
1926 convertParameterAttrs(attrsOp->getLoc(), argAttrs);
1927 if (failed(attrBuilder))
1928 return failure();
1929 call->addParamAttrs(argIdx, *attrBuilder);
1930 }
1931 }
1932
1933 // Convert the result attributes.
1934 if (ArrayAttr resAttrsArray = attrsOp.getResAttrsAttr()) {
1935 if (!resAttrsArray.empty()) {
1936 auto resAttrs = cast<DictionaryAttr>(resAttrsArray[0]);
1937 FailureOr<llvm::AttrBuilder> attrBuilder =
1938 convertParameterAttrs(attrsOp->getLoc(), resAttrs);
1939 if (failed(attrBuilder))
1940 return failure();
1941 call->addRetAttrs(*attrBuilder);
1942 }
1943 }
1944
1945 return success();
1946}
1947
1948std::optional<llvm::Attribute>
1950 if (auto str = dyn_cast<StringAttr>(a))
1951 return llvm::Attribute::get(ctx, ("no-builtin-" + str.getValue()).str());
1952 return std::nullopt;
1953}
1954
1955std::optional<llvm::Attribute>
1957 mlir::NamedAttribute namedAttr) {
1958 StringAttr name = namedAttr.getName();
1959 Attribute value = namedAttr.getValue();
1960
1961 if (auto strVal = dyn_cast<StringAttr>(value))
1962 return llvm::Attribute::get(ctx, name.getValue(), strVal.getValue());
1963 if (mlir::isa<UnitAttr>(value))
1964 return llvm::Attribute::get(ctx, name.getValue());
1965 return std::nullopt;
1966}
1967
1968FailureOr<llvm::AttrBuilder>
1969ModuleTranslation::convertParameterAttrs(Location loc,
1970 DictionaryAttr paramAttrs) {
1971 llvm::AttrBuilder attrBuilder(llvmModule->getContext());
1972 auto attrNameToKindMapping = getAttrNameToKindMapping();
1973
1974 for (auto namedAttr : paramAttrs) {
1975 auto it = attrNameToKindMapping.find(namedAttr.getName());
1976 if (it != attrNameToKindMapping.end()) {
1977 llvm::Attribute::AttrKind llvmKind = it->second;
1978 if (failed(convertParameterAttr(attrBuilder, llvmKind, namedAttr, *this,
1979 loc)))
1980 return failure();
1981 }
1982 }
1983
1984 return attrBuilder;
1985}
1986
1987LogicalResult ModuleTranslation::convertFunctionSignatures() {
1988 // Declare all functions first because there may be function calls that form a
1989 // call graph with cycles, or global initializers that reference functions.
1990 for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
1991 llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction(
1992 function.getName(),
1993 cast<llvm::FunctionType>(convertType(function.getFunctionType())));
1994 llvm::Function *llvmFunc = cast<llvm::Function>(llvmFuncCst.getCallee());
1995 llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
1996 llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
1997 mapFunction(function.getName(), llvmFunc);
1998 addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
1999
2000 // Convert function attributes.
2001 convertFunctionAttributes(*this, function, llvmFunc);
2002
2003 // Convert function kernel attributes to metadata.
2004 convertFunctionKernelAttributes(function, llvmFunc, *this);
2005
2006 // Convert function_entry_count attribute to metadata.
2007 if (std::optional<uint64_t> entryCount = function.getFunctionEntryCount())
2008 llvmFunc->setEntryCount(entryCount.value());
2009
2010 // Convert result attributes.
2011 if (ArrayAttr allResultAttrs = function.getAllResultAttrs()) {
2012 DictionaryAttr resultAttrs = cast<DictionaryAttr>(allResultAttrs[0]);
2013 FailureOr<llvm::AttrBuilder> attrBuilder =
2014 convertParameterAttrs(function, -1, resultAttrs);
2015 if (failed(attrBuilder))
2016 return failure();
2017 llvmFunc->addRetAttrs(*attrBuilder);
2018 }
2019
2020 // Convert argument attributes.
2021 for (auto [argIdx, llvmArg] : llvm::enumerate(llvmFunc->args())) {
2022 if (DictionaryAttr argAttrs = function.getArgAttrDict(argIdx)) {
2023 FailureOr<llvm::AttrBuilder> attrBuilder =
2024 convertParameterAttrs(function, argIdx, argAttrs);
2025 if (failed(attrBuilder))
2026 return failure();
2027 llvmArg.addAttrs(*attrBuilder);
2028 }
2029 }
2030
2031 // Forward the pass-through attributes to LLVM.
2032 FailureOr<llvm::AttrBuilder> convertedPassthroughAttrs =
2033 convertMLIRAttributesToLLVM(function.getLoc(), llvmFunc->getContext(),
2034 function.getPassthroughAttr(),
2035 function.getPassthroughAttrName());
2036 if (failed(convertedPassthroughAttrs))
2037 return failure();
2038 llvmFunc->addFnAttrs(*convertedPassthroughAttrs);
2039
2040 // Convert visibility attribute.
2041 llvmFunc->setVisibility(convertVisibilityToLLVM(function.getVisibility_()));
2042
2043 // Convert the comdat attribute.
2044 if (std::optional<mlir::SymbolRefAttr> comdat = function.getComdat()) {
2045 auto selectorOp = cast<ComdatSelectorOp>(
2046 SymbolTable::lookupNearestSymbolFrom(function, *comdat));
2047 llvmFunc->setComdat(comdatMapping.lookup(selectorOp));
2048 }
2049
2050 if (auto gc = function.getGarbageCollector())
2051 llvmFunc->setGC(gc->str());
2052
2053 if (auto unnamedAddr = function.getUnnamedAddr())
2054 llvmFunc->setUnnamedAddr(convertUnnamedAddrToLLVM(*unnamedAddr));
2055
2056 if (auto alignment = function.getAlignment())
2057 llvmFunc->setAlignment(llvm::MaybeAlign(*alignment));
2058
2059 // Translate the debug information for this function.
2060 debugTranslation->translate(function, *llvmFunc);
2061 }
2062
2063 return success();
2064}
2065
2066LogicalResult ModuleTranslation::convertFunctions() {
2067 // Convert functions.
2068 for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
2069 // Do not convert external functions, but do process dialect attributes
2070 // attached to them.
2071 if (function.isExternal()) {
2072 if (failed(convertDialectAttributes(function, {})))
2073 return failure();
2074 continue;
2075 }
2076
2077 if (failed(convertOneFunction(function)))
2078 return failure();
2079 }
2080
2081 return success();
2082}
2083
2084LogicalResult ModuleTranslation::convertIFuncs() {
2085 for (auto op : getModuleBody(mlirModule).getOps<IFuncOp>()) {
2086 llvm::Type *type = convertType(op.getIFuncType());
2087 llvm::GlobalValue::LinkageTypes linkage =
2088 convertLinkageToLLVM(op.getLinkage());
2089 llvm::Constant *resolver;
2090 if (auto *resolverFn = lookupFunction(op.getResolver())) {
2091 resolver = cast<llvm::Constant>(resolverFn);
2092 } else {
2093 Operation *aliasOp = symbolTable().lookupSymbolIn(parentLLVMModule(op),
2094 op.getResolverAttr());
2095 resolver = cast<llvm::Constant>(lookupAlias(aliasOp));
2096 }
2097
2098 auto *ifunc =
2099 llvm::GlobalIFunc::create(type, op.getAddressSpace(), linkage,
2100 op.getSymName(), resolver, llvmModule.get());
2101 addRuntimePreemptionSpecifier(op.getDsoLocal(), ifunc);
2102 ifunc->setUnnamedAddr(convertUnnamedAddrToLLVM(op.getUnnamedAddr()));
2103 ifunc->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
2104
2105 ifuncMapping.try_emplace(op, ifunc);
2106 }
2107
2108 return success();
2109}
2110
2111LogicalResult ModuleTranslation::convertComdats() {
2112 for (auto comdatOp : getModuleBody(mlirModule).getOps<ComdatOp>()) {
2113 for (auto selectorOp : comdatOp.getOps<ComdatSelectorOp>()) {
2114 llvm::Module *module = getLLVMModule();
2115 if (module->getComdatSymbolTable().contains(selectorOp.getSymName()))
2116 return emitError(selectorOp.getLoc())
2117 << "comdat selection symbols must be unique even in different "
2118 "comdat regions";
2119 llvm::Comdat *comdat = module->getOrInsertComdat(selectorOp.getSymName());
2120 comdat->setSelectionKind(convertComdatToLLVM(selectorOp.getComdat()));
2121 comdatMapping.try_emplace(selectorOp, comdat);
2122 }
2123 }
2124 return success();
2125}
2126
2127LogicalResult ModuleTranslation::convertUnresolvedBlockAddress() {
2128 for (auto &[blockAddressOp, llvmCst] : unresolvedBlockAddressMapping) {
2129 BlockAddressAttr blockAddressAttr = blockAddressOp.getBlockAddr();
2130 llvm::BasicBlock *llvmBlock = lookupBlockAddress(blockAddressAttr);
2131 assert(llvmBlock && "expected LLVM blocks to be already translated");
2132
2133 // Update mapping with new block address constant.
2134 auto *llvmBlockAddr = llvm::BlockAddress::get(
2135 lookupFunction(blockAddressAttr.getFunction().getValue()), llvmBlock);
2136 llvmCst->replaceAllUsesWith(llvmBlockAddr);
2137 assert(llvmCst->use_empty() && "expected all uses to be replaced");
2138 cast<llvm::GlobalVariable>(llvmCst)->eraseFromParent();
2139 }
2140 unresolvedBlockAddressMapping.clear();
2141 return success();
2142}
2143
2144void ModuleTranslation::setAccessGroupsMetadata(AccessGroupOpInterface op,
2145 llvm::Instruction *inst) {
2146 if (llvm::MDNode *node = loopAnnotationTranslation->getAccessGroups(op))
2147 inst->setMetadata(llvm::LLVMContext::MD_access_group, node);
2148}
2149
2150llvm::MDNode *
2151ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
2152 auto [scopeIt, scopeInserted] =
2153 aliasScopeMetadataMapping.try_emplace(aliasScopeAttr, nullptr);
2154 if (!scopeInserted)
2155 return scopeIt->second;
2156 llvm::LLVMContext &ctx = llvmModule->getContext();
2157 auto dummy = llvm::MDNode::getTemporary(ctx, {});
2158 // Convert the domain metadata node if necessary.
2159 auto [domainIt, insertedDomain] = aliasDomainMetadataMapping.try_emplace(
2160 aliasScopeAttr.getDomain(), nullptr);
2161 if (insertedDomain) {
2163 // Placeholder for potential self-reference.
2164 operands.push_back(dummy.get());
2165 if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
2166 operands.push_back(llvm::MDString::get(ctx, description));
2167 domainIt->second = llvm::MDNode::get(ctx, operands);
2168 // Self-reference for uniqueness.
2169 llvm::Metadata *replacement;
2170 if (auto stringAttr =
2171 dyn_cast<StringAttr>(aliasScopeAttr.getDomain().getId()))
2172 replacement = llvm::MDString::get(ctx, stringAttr.getValue());
2173 else
2174 replacement = domainIt->second;
2175 domainIt->second->replaceOperandWith(0, replacement);
2176 }
2177 // Convert the scope metadata node.
2178 assert(domainIt->second && "Scope's domain should already be valid");
2180 // Placeholder for potential self-reference.
2181 operands.push_back(dummy.get());
2182 operands.push_back(domainIt->second);
2183 if (StringAttr description = aliasScopeAttr.getDescription())
2184 operands.push_back(llvm::MDString::get(ctx, description));
2185 scopeIt->second = llvm::MDNode::get(ctx, operands);
2186 // Self-reference for uniqueness.
2187 llvm::Metadata *replacement;
2188 if (auto stringAttr = dyn_cast<StringAttr>(aliasScopeAttr.getId()))
2189 replacement = llvm::MDString::get(ctx, stringAttr.getValue());
2190 else
2191 replacement = scopeIt->second;
2192 scopeIt->second->replaceOperandWith(0, replacement);
2193 return scopeIt->second;
2194}
2195
2197 ArrayRef<AliasScopeAttr> aliasScopeAttrs) {
2199 nodes.reserve(aliasScopeAttrs.size());
2200 for (AliasScopeAttr aliasScopeAttr : aliasScopeAttrs)
2201 nodes.push_back(getOrCreateAliasScope(aliasScopeAttr));
2202 return llvm::MDNode::get(getLLVMContext(), nodes);
2203}
2204
2205void ModuleTranslation::setAliasScopeMetadata(AliasAnalysisOpInterface op,
2206 llvm::Instruction *inst) {
2207 auto populateScopeMetadata = [&](ArrayAttr aliasScopeAttrs, unsigned kind) {
2208 if (!aliasScopeAttrs || aliasScopeAttrs.empty())
2209 return;
2210 llvm::MDNode *node = getOrCreateAliasScopes(
2211 llvm::to_vector(aliasScopeAttrs.getAsRange<AliasScopeAttr>()));
2212 inst->setMetadata(kind, node);
2213 };
2214
2215 populateScopeMetadata(op.getAliasScopesOrNull(),
2216 llvm::LLVMContext::MD_alias_scope);
2217 populateScopeMetadata(op.getNoAliasScopesOrNull(),
2218 llvm::LLVMContext::MD_noalias);
2219}
2220
2221llvm::MDNode *ModuleTranslation::getTBAANode(TBAATagAttr tbaaAttr) const {
2222 return tbaaMetadataMapping.lookup(tbaaAttr);
2223}
2224
2225void ModuleTranslation::setTBAAMetadata(AliasAnalysisOpInterface op,
2226 llvm::Instruction *inst) {
2227 ArrayAttr tagRefs = op.getTBAATagsOrNull();
2228 if (!tagRefs || tagRefs.empty())
2229 return;
2230
2231 // LLVM IR currently does not support attaching more than one TBAA access tag
2232 // to a memory accessing instruction. It may be useful to support this in
2233 // future, but for the time being just ignore the metadata if MLIR operation
2234 // has multiple access tags.
2235 if (tagRefs.size() > 1) {
2236 op.emitWarning() << "TBAA access tags were not translated, because LLVM "
2237 "IR only supports a single tag per instruction";
2238 return;
2239 }
2240
2241 llvm::MDNode *node = getTBAANode(cast<TBAATagAttr>(tagRefs[0]));
2242 inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
2243}
2244
2246 DereferenceableOpInterface op, llvm::Instruction *inst) {
2247 DereferenceableAttr derefAttr = op.getDereferenceableOrNull();
2248 if (!derefAttr)
2249 return;
2250
2251 llvm::MDNode *derefSizeNode = llvm::MDNode::get(
2253 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
2254 llvm::IntegerType::get(getLLVMContext(), 64), derefAttr.getBytes())));
2255 unsigned kindId = derefAttr.getMayBeNull()
2256 ? llvm::LLVMContext::MD_dereferenceable_or_null
2257 : llvm::LLVMContext::MD_dereferenceable;
2258 inst->setMetadata(kindId, derefSizeNode);
2259}
2260
2261void ModuleTranslation::setBranchWeightsMetadata(WeightedBranchOpInterface op) {
2262 SmallVector<uint32_t> weights;
2263 llvm::transform(op.getWeights(), std::back_inserter(weights),
2264 [](int32_t value) { return static_cast<uint32_t>(value); });
2265 if (weights.empty())
2266 return;
2267
2268 llvm::Instruction *inst = isa<CallOp>(op) ? lookupCall(op) : lookupBranch(op);
2269 assert(inst && "expected the operation to have a mapping to an instruction");
2270 inst->setMetadata(
2271 llvm::LLVMContext::MD_prof,
2272 llvm::MDBuilder(getLLVMContext()).createBranchWeights(weights));
2273}
2274
2275LogicalResult ModuleTranslation::createTBAAMetadata() {
2276 llvm::LLVMContext &ctx = llvmModule->getContext();
2277 llvm::IntegerType *offsetTy = llvm::IntegerType::get(ctx, 64);
2278
2279 // Walk the entire module and create all metadata nodes for the TBAA
2280 // attributes. The code below relies on two invariants of the
2281 // `AttrTypeWalker`:
2282 // 1. Attributes are visited in post-order: Since the attributes create a DAG,
2283 // this ensures that any lookups into `tbaaMetadataMapping` for child
2284 // attributes succeed.
2285 // 2. Attributes are only ever visited once: This way we don't leak any
2286 // LLVM metadata instances.
2287 AttrTypeWalker walker;
2288 walker.addWalk([&](TBAARootAttr root) {
2289 llvm::MDNode *node;
2290 if (StringAttr id = root.getId()) {
2291 node = llvm::MDNode::get(ctx, llvm::MDString::get(ctx, id));
2292 } else {
2293 // Anonymous root nodes are self-referencing.
2294 auto selfRef = llvm::MDNode::getTemporary(ctx, {});
2295 node = llvm::MDNode::get(ctx, {selfRef.get()});
2296 node->replaceOperandWith(0, node);
2297 }
2298 tbaaMetadataMapping.insert({root, node});
2299 });
2300
2301 walker.addWalk([&](TBAATypeDescriptorAttr descriptor) {
2302 SmallVector<llvm::Metadata *> operands;
2303 operands.push_back(llvm::MDString::get(ctx, descriptor.getId()));
2304 for (TBAAMemberAttr member : descriptor.getMembers()) {
2305 operands.push_back(tbaaMetadataMapping.lookup(member.getTypeDesc()));
2306 operands.push_back(llvm::ConstantAsMetadata::get(
2307 llvm::ConstantInt::get(offsetTy, member.getOffset())));
2308 }
2309
2310 tbaaMetadataMapping.insert({descriptor, llvm::MDNode::get(ctx, operands)});
2311 });
2312
2313 walker.addWalk([&](TBAATagAttr tag) {
2314 SmallVector<llvm::Metadata *> operands;
2315
2316 operands.push_back(tbaaMetadataMapping.lookup(tag.getBaseType()));
2317 operands.push_back(tbaaMetadataMapping.lookup(tag.getAccessType()));
2318
2319 operands.push_back(llvm::ConstantAsMetadata::get(
2320 llvm::ConstantInt::get(offsetTy, tag.getOffset())));
2321 if (tag.getConstant())
2322 operands.push_back(
2323 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(offsetTy, 1)));
2324
2325 tbaaMetadataMapping.insert({tag, llvm::MDNode::get(ctx, operands)});
2326 });
2327
2328 mlirModule->walk([&](AliasAnalysisOpInterface analysisOpInterface) {
2329 if (auto attr = analysisOpInterface.getTBAATagsOrNull())
2330 walker.walk(attr);
2331 });
2332
2333 return success();
2334}
2335
2336LogicalResult ModuleTranslation::createIdentMetadata() {
2337 if (auto attr = mlirModule->getAttrOfType<StringAttr>(
2338 LLVMDialect::getIdentAttrName())) {
2339 StringRef ident = attr;
2340 llvm::LLVMContext &ctx = llvmModule->getContext();
2341 llvm::NamedMDNode *namedMd =
2342 llvmModule->getOrInsertNamedMetadata(LLVMDialect::getIdentAttrName());
2343 llvm::MDNode *md = llvm::MDNode::get(ctx, llvm::MDString::get(ctx, ident));
2344 namedMd->addOperand(md);
2345 }
2346
2347 return success();
2348}
2349
2350LogicalResult ModuleTranslation::createCommandlineMetadata() {
2351 if (auto attr = mlirModule->getAttrOfType<StringAttr>(
2352 LLVMDialect::getCommandlineAttrName())) {
2353 StringRef cmdLine = attr;
2354 llvm::LLVMContext &ctx = llvmModule->getContext();
2355 llvm::NamedMDNode *nmd = llvmModule->getOrInsertNamedMetadata(
2356 LLVMDialect::getCommandlineAttrName());
2357 llvm::MDNode *md =
2358 llvm::MDNode::get(ctx, llvm::MDString::get(ctx, cmdLine));
2359 nmd->addOperand(md);
2360 }
2361
2362 return success();
2363}
2364
2365LogicalResult ModuleTranslation::createDependentLibrariesMetadata() {
2366 if (auto dependentLibrariesAttr = mlirModule->getDiscardableAttr(
2367 LLVM::LLVMDialect::getDependentLibrariesAttrName())) {
2368 auto *nmd =
2369 llvmModule->getOrInsertNamedMetadata("llvm.dependent-libraries");
2370 llvm::LLVMContext &ctx = llvmModule->getContext();
2371 for (auto libAttr :
2372 cast<ArrayAttr>(dependentLibrariesAttr).getAsRange<StringAttr>()) {
2373 auto *md =
2374 llvm::MDNode::get(ctx, llvm::MDString::get(ctx, libAttr.getValue()));
2375 nmd->addOperand(md);
2376 }
2377 }
2378 return success();
2379}
2380
2382 llvm::Instruction *inst) {
2383 LoopAnnotationAttr attr =
2385 .Case<LLVM::BrOp, LLVM::CondBrOp>(
2386 [](auto branchOp) { return branchOp.getLoopAnnotationAttr(); });
2387 if (!attr)
2388 return;
2389 llvm::MDNode *loopMD =
2390 loopAnnotationTranslation->translateLoopAnnotation(attr, op);
2391 inst->setMetadata(llvm::LLVMContext::MD_loop, loopMD);
2392}
2393
2394void ModuleTranslation::setDisjointFlag(Operation *op, llvm::Value *value) {
2395 auto iface = cast<DisjointFlagInterface>(op);
2396 // We do a dyn_cast here in case the value got folded into a constant.
2397 if (auto *disjointInst = dyn_cast<llvm::PossiblyDisjointInst>(value))
2398 disjointInst->setIsDisjoint(iface.getIsDisjoint());
2399}
2400
2402 return typeTranslator.translateType(type);
2403}
2404
2405/// A helper to look up remapped operands in the value remapping table.
2408 remapped.reserve(values.size());
2409 for (Value v : values)
2410 remapped.push_back(lookupValue(v));
2411 return remapped;
2412}
2413
2414llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
2415 if (!ompBuilder) {
2416 ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
2417
2418 // Flags represented as top-level OpenMP dialect attributes are set in
2419 // `OpenMPDialectLLVMIRTranslationInterface::amendOperation()`. Here we set
2420 // the default configuration.
2421 llvm::OpenMPIRBuilderConfig config(
2422 /* IsTargetDevice = */ false, /* IsGPU = */ false,
2423 /* OpenMPOffloadMandatory = */ false,
2424 /* HasRequiresReverseOffload = */ false,
2425 /* HasRequiresUnifiedAddress = */ false,
2426 /* HasRequiresUnifiedSharedMemory = */ false,
2427 /* HasRequiresDynamicAllocators = */ false);
2428 unsigned int defaultAS =
2429 llvmModule->getDataLayout().getProgramAddressSpace();
2430 config.setDefaultTargetAS(defaultAS);
2431 config.setRuntimeCC(llvmModule->getTargetTriple().isSPIRV()
2432 ? llvm::CallingConv::SPIR_FUNC
2433 : llvm::CallingConv::C);
2434 ompBuilder->setConfig(std::move(config));
2435 ompBuilder->initialize();
2436 }
2437 return ompBuilder.get();
2438}
2439
2440llvm::vfs::FileSystem &ModuleTranslation::getFileSystem() {
2441 if (fileSystem)
2442 return *fileSystem;
2443 return *llvm::vfs::getRealFileSystem();
2444}
2445
2447 llvm::DILocalScope *scope) {
2448 return debugTranslation->translateLoc(loc, scope);
2449}
2450
2451llvm::DIExpression *
2452ModuleTranslation::translateExpression(LLVM::DIExpressionAttr attr) {
2453 return debugTranslation->translateExpression(attr);
2454}
2455
2456llvm::DIGlobalVariableExpression *
2458 LLVM::DIGlobalVariableExpressionAttr attr) {
2459 return debugTranslation->translateGlobalVariableExpression(attr);
2460}
2461
2463 return debugTranslation->translate(attr);
2464}
2465
2466llvm::RoundingMode
2467ModuleTranslation::translateRoundingMode(LLVM::RoundingMode rounding) {
2468 return convertRoundingModeToLLVM(rounding);
2469}
2470
2472 LLVM::FPExceptionBehavior exceptionBehavior) {
2473 return convertFPExceptionBehaviorToLLVM(exceptionBehavior);
2474}
2475
2476llvm::NamedMDNode *
2478 return llvmModule->getOrInsertNamedMetadata(name);
2479}
2480
2481static std::unique_ptr<llvm::Module>
2482prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
2483 StringRef name) {
2484 m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
2485 auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
2486 if (auto dataLayoutAttr =
2487 m->getDiscardableAttr(LLVM::LLVMDialect::getDataLayoutAttrName())) {
2488 llvmModule->setDataLayout(cast<StringAttr>(dataLayoutAttr).getValue());
2489 } else {
2490 FailureOr<llvm::DataLayout> llvmDataLayout(llvm::DataLayout(""));
2491 if (auto iface = dyn_cast<DataLayoutOpInterface>(m)) {
2492 if (DataLayoutSpecInterface spec = iface.getDataLayoutSpec()) {
2493 llvmDataLayout =
2494 translateDataLayout(spec, DataLayout(iface), m->getLoc());
2495 }
2496 } else if (auto mod = dyn_cast<ModuleOp>(m)) {
2497 if (DataLayoutSpecInterface spec = mod.getDataLayoutSpec()) {
2498 llvmDataLayout =
2499 translateDataLayout(spec, DataLayout(mod), m->getLoc());
2500 }
2501 }
2502 if (failed(llvmDataLayout))
2503 return nullptr;
2504 llvmModule->setDataLayout(*llvmDataLayout);
2505 }
2506 if (auto targetTripleAttr =
2507 m->getDiscardableAttr(LLVM::LLVMDialect::getTargetTripleAttrName()))
2508 llvmModule->setTargetTriple(
2509 llvm::Triple(cast<StringAttr>(targetTripleAttr).getValue()));
2510
2511 if (auto asmAttr = m->getDiscardableAttr(
2512 LLVM::LLVMDialect::getModuleLevelAsmAttrName())) {
2513 auto asmArrayAttr = dyn_cast<ArrayAttr>(asmAttr);
2514 if (!asmArrayAttr) {
2515 m->emitError("expected an array attribute for a module level asm");
2516 return nullptr;
2517 }
2518
2519 for (Attribute elt : asmArrayAttr) {
2520 auto asmStrAttr = dyn_cast<StringAttr>(elt);
2521 if (!asmStrAttr) {
2522 m->emitError(
2523 "expected a string attribute for each entry of a module level asm");
2524 return nullptr;
2525 }
2526 llvmModule->appendModuleInlineAsm(asmStrAttr.getValue());
2527 }
2528 }
2529
2530 return llvmModule;
2531}
2532
2533std::unique_ptr<llvm::Module>
2534mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
2535 StringRef name, bool disableVerification,
2536 llvm::vfs::FileSystem *fs) {
2537 if (!satisfiesLLVMModule(module)) {
2538 module->emitOpError("can not be translated to an LLVMIR module");
2539 return nullptr;
2540 }
2541
2542 std::unique_ptr<llvm::Module> llvmModule =
2543 prepareLLVMModule(module, llvmContext, name);
2544 if (!llvmModule)
2545 return nullptr;
2546
2549
2550 ModuleTranslation translator(module, std::move(llvmModule), fs);
2551 llvm::IRBuilder<llvm::TargetFolder> llvmBuilder(
2552 llvmContext,
2553 llvm::TargetFolder(translator.getLLVMModule()->getDataLayout()));
2554
2555 // Convert module before functions and operations inside, so dialect
2556 // attributes can be used to change dialect-specific global configurations via
2557 // `amendOperation()`. These configurations can then influence the translation
2558 // of operations afterwards.
2559 if (failed(translator.convertOperation(*module, llvmBuilder)))
2560 return nullptr;
2561
2562 if (failed(translator.convertComdats()))
2563 return nullptr;
2564 if (failed(translator.convertFunctionSignatures()))
2565 return nullptr;
2566 if (failed(translator.convertGlobalsAndAliases()))
2567 return nullptr;
2568 if (failed(translator.convertIFuncs()))
2569 return nullptr;
2570 if (failed(translator.createTBAAMetadata()))
2571 return nullptr;
2572 if (failed(translator.createIdentMetadata()))
2573 return nullptr;
2574 if (failed(translator.createCommandlineMetadata()))
2575 return nullptr;
2576 if (failed(translator.createDependentLibrariesMetadata()))
2577 return nullptr;
2578
2579 // Convert other top-level operations if possible.
2580 for (Operation &o : getModuleBody(module).getOperations()) {
2581 if (!isa<LLVM::LLVMFuncOp, LLVM::AliasOp, LLVM::GlobalOp,
2582 LLVM::GlobalCtorsOp, LLVM::GlobalDtorsOp, LLVM::ComdatOp,
2583 LLVM::IFuncOp>(&o) &&
2584 !o.hasTrait<OpTrait::IsTerminator>() &&
2585 failed(translator.convertOperation(o, llvmBuilder))) {
2586 return nullptr;
2587 }
2588 }
2589
2590 // Operations in function bodies with symbolic references must be converted
2591 // after the top-level operations they refer to are declared, so we do it
2592 // last.
2593 if (failed(translator.convertFunctions()))
2594 return nullptr;
2595
2596 // Now that all MLIR blocks are resolved into LLVM ones, patch block address
2597 // constants to point to the correct blocks.
2598 if (failed(translator.convertUnresolvedBlockAddress()))
2599 return nullptr;
2600
2601 // Add the necessary debug info module flags, if they were not encoded in MLIR
2602 // beforehand.
2603 translator.debugTranslation->addModuleFlagsIfNotPresent();
2604
2605 // Call the OpenMP IR Builder callbacks prior to verifying the module
2606 if (auto *ompBuilder = translator.getOpenMPBuilder())
2607 ompBuilder->finalize();
2608
2609 if (!disableVerification &&
2610 llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
2611 return nullptr;
2612
2613 return std::move(translator.llvmModule);
2614}
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