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